2011-05-02 13 views
13

Estoy planeando crear una vista usando este SQL SELECT, pero la explicación para él muestra que está usando temporal y usando filesort. No puedo descifrar qué índices necesito para solucionar este problema. Principalmente, me pregunto por qué está usando filesort intead de usar un índice para ordenar.MySQL Explicación: ¿Qué está causando 'El uso temporal; Usando filesort '

Éstos son mis tablas:

CREATE TABLE `learning_signatures` (
    `signature_id` int(11) NOT NULL AUTO_INCREMENT, 
    `signature_file` varchar(100) NOT NULL, 
    `signature_md5` varchar(32) NOT NULL, 
    `image_file` varchar(100) NOT NULL, 
    PRIMARY KEY (`signature_id`), 
    UNIQUE KEY `unique_signature_md5` (`signature_md5`) 
) ENGINE=InnoDB AUTO_INCREMENT=640 DEFAULT CHARSET=latin1 

CREATE TABLE `learning_user_suggestions` (
    `user_suggestion_id` int(11) NOT NULL AUTO_INCREMENT, 
    `signature_id` int(11) NOT NULL, 
    `ch` char(1) NOT NULL, 
    `time_suggested` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `user_id` int(11) NOT NULL, 
    PRIMARY KEY (`user_suggestion_id`), 
    KEY `char_index` (`ch`), 
    KEY `ls_sig_id_indx` (`signature_id`), 
    KEY `user_id_indx` (`user_id`), 
    KEY `sig_char_indx` (`signature_id`,`ch`) 
) ENGINE=InnoDB AUTO_INCREMENT=1173 DEFAULT CHARSET=latin1 

Y aquí es la instrucción SQL problemático que estoy planeando sobre el uso en mi opinión:

select ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, sug.ch , count(sug.ch) AS suggestion_count 
from (`learning_signatures` `ls` left join `learning_user_suggestions` `sug` on(ls.signature_id = sug.signature_id)) 
group by ls.signature_id, sug.ch; 

salida de explicar:

id select_type table type possible_keys     key    key_len ref     rows Extra 
1 SIMPLE  ls  ALL  NULL       NULL   NULL NULL    514  "Using temporary; Using filesort" 
1 SIMPLE  sug  ref  ls_sig_id_indx,sig_char_indx ls_sig_id_indx 4  wwf.ls.signature_id 1 

Otro ejemplo, esta vez usando una cláusula where:

explain select ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, sug.ch , count(sug.ch) AS suggestion_count 
from (`learning_signatures` `ls` left join `learning_user_suggestions` `sug` on(ls.signature_id = sug.signature_id)) 
WHERE signature_md5 = '75f8a5b1176ecc2487b90bacad9bc4c' 
group by ls.signature_id, sug.ch; 

Explicar salida:

id select_type table type possible_keys    key     key_len ref  rows Extra 
1 SIMPLE  ls  const unique_signature_md5   unique_signature_md5 34  const 1  "Using temporary; Using filesort" 
1 SIMPLE  sug  ref  ls_sig_id_indx,sig_char_indx ls_sig_id_indx   4  const 1 
+1

Publicar salida EXPLAIN, publicar su declaración CREATE VIEW ... –

+0

Buen punto, acabo de agregar el resultado de explicación. Todavía no he creado la vista, quiero optimizar el SELECCIONAR primero – bradvido

+2

Entonces, ¿qué es exactamente lo incorrecto aquí?No tiene un factor que limite el conjunto de datos, se extraerá toda la tabla de firmas_aprendizaje. El uso temporal es probablemente debido a su tamaño innodb_buffer_pool. –

Respuesta

18

En su primera consulta, lo que hace es unirse a la tabla de firmas con sugerencias de los usuarios, obtener muchas filas y luego agrupar los resultados usando algunas columnas de las sugerencias de los usuarios. Pero no hay un índice para la tabla unida que ayude con la agrupación, ya que tendría que definirse en una tabla previamente unida. Lo que en su lugar debe hacer es tratar de crear una tabla derivada de sugerencias de los usuarios que ya está agrupadas por CH y signature_id y luego se unen a ella:

SELECT ls.signature_id, ls.signature_file, ls.signature_md5, ls.image_file, 
     sug.ch, sug.suggestion_count 
FROM learning_signatures ls 
LEFT JOIN 
    (SELECT s.signature_id, s.ch, count(s.ch) as suggestion_count 
    FROM learning_user_suggestions s 
    GROUP BY s.signature_id, s.ch) as sug 
ON ls.signature_id = sug.signature_id 

Optimizer debe ser capaz ahora de usar el índice de sig_char_indx para enfajadora, la La tabla derivada no será más grande que la tabla de firmas y se unirá a ambas utilizando una columna única. Aún tendrá que hacer un escaneo completo de la tabla de firmas, pero eso no puede evitarse porque de todos modos está seleccionando todo.

En cuanto a la segunda consulta, si desea restringir firmas para una sola simplemente añada

WHERE ls.signature_md5='75f8a5b1176ecc2487b90bacad9bc4c' 

hasta el final de la consulta previa y el grupo sólo s.ch, ya que sólo un signature_id coincidirá con su md5 de todos modos. El optimizador ahora debería usar el índice md5 para where y char_index para agrupar.

+0

Excelente. Esto funcionó bien, y el optimizador funcionó como lo describió con su consulta. Gracias por la explicación detallada también, ahora veo la diferencia. – bradvido

0

Tal vez que va a ayudar si se crea un índice en learning_signatures que contiene tanto signature_md5 y signature_id (y en ese orden)

`KEY `md5_id` (`signature_md5`,`signature_id`)? 

No soy Experto en MySQL, pero encontré que las claves creadas que encapsulan tanto la cláusula where como la cláusula join generalmente ayudan a deshacerse de los archivos temporales y filesort

+0

Gracias por la consejo, pero lo probé y no eliminó el archivo temporal o el archivo. – bradvido

-1

Indices de uso. Busque los campos donde los necesita mediante el EXPLAIN en sus consultas.

Sin embargo, si tiene una base de datos principalmente de solo escritura (pocas lecturas), es posible que desee evitar el uso de índices, ya que pueden tener un impacto negativo en su rendimiento de escritura.

Cuestiones relacionadas