2011-09-19 28 views
7

Consulte la consulta a continuación. ¿Qué índice debería crear en la tabla para que la consulta use el índice y evite usar archivos temporales y filesort? Probé muchas combinaciones diferentes de índices y leí advice here, pero parece que no puedo resolverlo. Mi explicación dice Using Where (sin índice), o Using Where Using Temporary, Using FilesortÍndice de MySQL para Group By/Order By

Aquí hay una consulta simplificada. Todas las columnas son enteros.

SELECT c1, Sum(c2) 
FROM table 
WHERE c3 IS NOT NULL 
AND c4 = 2011 
AND c5 = 0 
AND c6 In (6,9,11) 
GROUP BY c1 
+1

Tenga en cuenta que MySQL solo puede usar un índice por tabla, de modo que si coloca un índice en una columna (s) para optimizar el GROUP BY puede terminar lastimándose a sí mismo ya que las cláusulas WHERE no se optimizan y finalmente se ha trabajado más por hacer (es decir, escaneo completo de la tabla). –

+3

Entiendo eso, pero ¿hay alguna forma de crear un único índice que pueda ser utilizado por las cláusulas GROUP BY y WHERE? – bradvido

Respuesta

7

Esto debería ayudarlo. Vuelva a escribir su consulta como sigue:

SELECT c1, Sum(c2) 
FROM table 
WHERE c4 = 2011 
AND c5 = 0 
AND c6 In (6,9,11) 
AND c3 IS NOT NULL 
GROUP BY c1 

Ahora cree un índice compuesto en las columnas (C4, C5, C6) con las columnas en ese orden. Las columnas en su índice deben aparecer en el mismo orden que las columnas en su cláusula WHERE. De lo contrario, el índice no funcionará. La selectividad de este índice es lo suficientemente estrecha como para que una clasificación de archivos en la tabla temporal (para el grupo por) sea rápida.

El motivo para mover c3 al final de la consulta es el siguiente. Como ejemplo, supongamos que c3 puede tomar valores entre 0 y 100 (o puede ser NULL). Si ejecuta una consulta "IS NOT NULL", Mysql necesita recorrer casi todo el índice B-Tree, excepto los bordes que corresponden a NULL. Por lo tanto, MySQL decide que una exploración de tabla completa es una opción más fácil que recorrer todas las diferentes rutas en el índice. Por otro lado, verá que si su consulta era "IS NULL" y su índice era (c3, c4, c5, c6) entonces Mysql de hecho usará este índice. Esto se debe a que en este caso Mysql solo necesita atravesar la parte del árbol de índice correspondiente al valor NULL.

El tipo de índices que necesita MySQL depende en gran medida de la consulta en cuestión. ¡Crear índices en todas las columnas, como @louis sugirió, NO es una buena idea!

+0

¡Gracias por la explicación detallada! – bradvido

+5

"Las columnas en su índice deben aparecer en el mismo orden que las columnas en su cláusula WHERE. De lo contrario, el índice no funcionará". Al optimizador de consultas no le importa cómo se ordena la cláusula 'WHERE'. 'SELECCIONAR ...FROM foo WHERE bar = 1 AND baz <5' tendrá exactamente el mismo plan de ejecución que 'SELECT ... FROM foo WHERE baz <5 AND bar = 1', y usar índices exactamente de la misma manera. El tipo de condición (igualdad o desigualdad, selectiva o no) es lo importante, no dónde aparece en la cláusula 'WHERE'. – Air

+0

No estoy seguro de que esto sea cierto. Según mi experiencia, importa el orden de la definición del índice, pero no el orden de la cláusula where. –

-1

Por experiencia, debería decir: construir índices para todas las columnas de la cláusula "donde" (pero en este caso, no c6)

Al menos, C4 y C5.

La cláusula "group by" ordenará los resultados. Si tiene muchos registros en el resultado, PUEDE ser útil también indexar c1.

c3 solo se ha probado como "no nulo". Pero indexarlo también puede mejorar las cosas, esto debe ser probado.

Hopz, esto fue útil.

0

Creo que el problema es con la cláusula 'ORDER BY 2 DESC'. Incluso si c2 está indexado, SUM (C2) no lo es.

En cuanto a los índices que 'deberías' tener, eso depende de los datos, así que no puedo realmente comentar.

+0

Por razones de argumentos, digamos que no estoy usando la cláusula ORDER BY. (Lo he eliminado de la pregunta). Todavía no puedo encontrar un índice para trabajar. – bradvido