En MySQL, ¿el orden de las columnas en una cláusula WHERE afecta el rendimiento de la consulta?

38

Tengo problemas de rendimiento en ciertas consultas de bases de datos que tienen grandes conjuntos de resultados posibles.

La consulta en cuestión, tengo tres ANDs en la cláusula WHERE

¿Importa el orden de las cláusulas?

Como en, si pongo la cláusula ASI_EVENT_TIME primero (ya que eso eliminaría la mayoría de los resultados de cualquiera de las cláusulas.

¿Mejorará eso el tiempo de ejecución de la consulta?

CONSULTA:

SELECT DISTINCT  activity_seismo_info.* 
FROM `activity_seismo_info` 
WHERE 
    activity_seismo_info.ASI_ACTIVITY_ID IS NOT NULL  AND 
    activity_seismo_info.ASI_SEISMO_ID IN (43,44,...,259) AND 
    (
        activity_seismo_info.ASI_EVENT_TIME>='2011-03-10 00:00:00' AND 
        activity_seismo_info.ASI_EVENT_TIME<='2011-03-17 23:59:59'
    ) 

ORDER BY activity_seismo_info.ASI_EVENT_TIME DESC

EXPLICAR la consulta:

+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
| id | select_type | table   | type  | possible_keys             | key          | key_len | ref  | rows  | Extra                       |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
|  1 | SIMPLE      | act...o | range | act...o_FI_1,act...o_FI_2 | act...o_FI_1 | 5       | NULL | 65412 | Using where; Using filesort |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+

Utilizando:

PHP 5.2

MySQL 5.0.51a-3ubuntu5.4

Propel 1.3

Symfony 1.2.5

Patricio
fuente
El ORDER BY es probablemente lo que está tomando tanto tiempo. "Usar filesort" puede ser extremadamente lento. He encontrado que hacer pedidos en la lógica de la aplicación MUCHO más rápido que usar ORDER BY.
maclema
Hice esta misma pregunta hace un tiempo (antes de este sitio) en stackoverflow. Consulte los enlaces para obtener las respuestas que recibí allí. stackoverflow.com/questions/3805863/…
Scott
2
@maclema: a menos que su aplicación se ejecute en una máquina mucho más rápida que su base de datos, su afirmación es ciertamente falsa, sin mencionar la carga inútil de toda esa lógica de clasificación en su aplicación. order bypertenece a la base de datos.
Jack Douglas

Respuestas:

24

No lo creo. El optimizador de consultas debe ser lo suficientemente inteligente.

Puede intentar reorganizar las cláusulas WHERE y ver que EXPLAINS le dice lo mismo en cada caso.


Acerca de lo que se puede hacer para optimizar esta consulta: ¿Hay un índice en ASI_EVENT_TIME? (Esto es lo más importante que creo para esta consulta, ya que también clasifica los resultados al usarlo).

¿Hay índices en los otros dos campos (ASI_SEISMO_ID y ASI_ACTIVITY_ID)?

Sería útil si publicara la estructura de la tabla.

ypercubeᵀᴹ
fuente
Nunca pensé en crear un índice de los tiempos del evento. Lo intentaré mañana en un dev db y veré si hay alguna diferencia notable.
Patrick
@Patrick Suponiendo que todas las demás consultas que usarían este índice están ordenando esta fecha en orden descendente, también querrá ordenar la clave de índice (activity_seismo_info.ASI_EVENT_TIME) en orden descendente.
Matt M
@MattM No sabía que PODRÍAS pedir una clave de índice. Impresionante Si ordeno la clave de índice, ¿eso afectará necesariamente el ordenamiento del rendimiento en la dirección opuesta hasta el punto de que es peor que ninguna clave de índice?
Patrick
@Patrick Tienes razón. Mi cerebro está atascado en la tierra de SQL Server. Puede especificar el orden de clasificación en MYSQL y se analizará, pero se ignora. Todos los índices se ordenan en orden ascendente en MYSQL. Perdón por la confusion.
Matt M
13

De la documentación :

Si la tabla tiene un índice de varias columnas, el optimizador puede utilizar cualquier prefijo más a la izquierda del índice para buscar filas. Por ejemplo, si tiene un índice de tres columnas en (col1, col2, col3), tiene capacidades de búsqueda indexadas en (col1), (col1, col2) y (col1, col2, col3).

MySQL no puede usar un índice si las columnas no forman un prefijo más a la izquierda del índice.

Entonces sí, debería ser el mismo que el orden de las columnas en un índice compuesto .

Gayo
fuente
44
Si la tabla tiene un índice de columnas múltiples, seleccionar columnas de la izquierda es importante, pero el orden en el que selecciona no importa. Entonces, si tiene el índice a, b, c y lo tiene WHERE c = 'foo' AND a = 'bar' AND b = 'foobar'y el índice aún es elegible para su uso.
texelate
10

No, no importa

El optimizador realiza un montón de transformaciones simples justo después de analizar el SQL; esta es una de ellas.

Morgan Tocker
fuente
8

Donde foo y bar

optimiza lo mismo que

DONDE bar y foo

Sin embargo,

DONDE no igual # 1 Y no igual # 2

No se pueden optimizar ambas partes. Por ejemplo,

DONDE a ENTRE 1 y 3 Yb> 17

no puede hacer un buen uso de INDEX (a, b) o INDEX (b, a)

Para expresarlo de manera diferente, cualquier prueba '=' Y juntas en la cláusula WHERE se usa primero, luego se puede manejar una no '=' (IN, BETWEEN,>, etc.). No más de uno puede ser optimizado efectivamente.

Su consulta tiene 3 de estas cláusulas.

Como resultado, el ÍNDICE (EVENT_TIME) es probablemente el más útil: ayudará con uno de los AND, y podría usarse para evitar "ordenar archivos" para ORDER BY.

Si no hay filas duplicadas (¿por qué habría de haberlas?), Elimine DISTINCT. Eso causa aún más esfuerzo.

Proporcione SHOW CREATE TABLE y SHOW TABLE STATUS cuando haga preguntas de rendimiento.

Actualización ... Las versiones más recientes (por ejemplo, MySQL 5.7) pueden, en algunas situaciones, tratarse IN( list of constants )casi como =. Para ir a lo seguro, siga este orden (cada parte es opcional):

  1. Cualquier cantidad de =.
  2. Algunos INs.
  3. A lo sumo un rango.
Rick James
fuente
1

MySQL donde el documento de optimización dice:

Es posible que tenga la tentación de volver a escribir sus consultas para agilizar las operaciones aritméticas, al tiempo que sacrifica la legibilidad. Debido a que MySQL realiza optimizaciones similares automáticamente , a menudo puede evitar este trabajo y dejar la consulta en una forma más comprensible y fácil de mantener. Algunas de las optimizaciones realizadas por MySQL son las siguientes:

  • ...

  • Para cada tabla en una combinación, se construye un WHERE más simple para obtener una evaluación rápida de WHERE para la tabla y también para omitir filas lo antes posible .

  • Se consulta cada índice de la tabla, y se utiliza el mejor índice a menos que el optimizador crea que es más eficiente usar un escaneo de la tabla . En un momento, se usó un escaneo en función de si el mejor índice abarcaba más del 30% de la tabla, pero un porcentaje fijo ya no determina la elección entre usar un índice o un escaneo. El optimizador ahora es más complejo y basa su estimación en factores adicionales como el tamaño de la tabla, el número de filas y el tamaño del bloque de E / S.

De esta manera, es racional que el optimizador de consultas omita el orden CÓMO utilizamos las columnas en la consulta (No solo MySQL sino SQL es un lenguaje declarativo y debe hacer lo que queremos, no cómo queremos).

Sin embargo, todavía me encanta tener el mismo tipo para las columnas de una clave compuesta en la consulta, pero a veces es inevitable, por ejemplo, cuando usamos ORM o ActiveRecord, en algunos marcos como yii2, la personalización de los criterios de relación se agregará al final de una condición "activada" pero aún necesitamos las capacidades de QueryBuilders en diferentes partes de una aplicación.

Alix
fuente
-2

CUALQUIER campo que se use en sus cláusulas WHERE / HAVING y tenga una alta selectividad (el número de valores únicos / el número total de registros> 10% ~ 20%) DEBE indexarse.

Entonces, si su ASI_EVENT_TIMEcolumna tiene muchos valores posibles, primero indexe todos. Luego, como le dijo @ypercube, intente reorganizarlos y vea lo que EXPLAIN le dice. Debería ser todo lo mismo.

Además, desea que eche un vistazo a la indexación de filtros SQL LIKE . Aunque no es para lo que necesita una respuesta, aún así aprenderá cómo funciona la indexación bajo el capó.

* Editar: consulte los enlaces que se proporcionan a continuación en los comentarios para obtener más información sobre la indexación.

Ojo
fuente
8
-1 Indexar cada columna NO es una mejor práctica. Cada índice le cuesta de múltiples maneras. Asegúrese de elegir buenos índices, que generalmente constarán de varias columnas, generalmente en el orden de selectividad y frecuencia utilizadas. Esto puede estar inclinado en SQL Server, pero la información del índice sigue siendo válida: sqlskills.com/BLOGS/KIMBERLY/post/… .
Eric Humphrey - lotsahelp
@Eric Humphrey +1 Para la explicación y el enlace al sitio de Kimberly.
Matt M
está equivocado, tener un índice en la columna a veces perjudica su rendimiento en consultas seleccionadas: mysqlperformanceblog.com/2007/08/28/… . NUNCA debe usar la regla general: a veces funciona, a veces no.
sumar
Bien, estoy de acuerdo. Sin embargo, esto es válido en caso de que la selectividad del valor sea baja. Teniendo en cuenta el tipo de datos que usa Patrick (el autor de esta pregunta), que es DATETIME, se recomienda la indexación. Por lo general, este tipo de campo tiene un conjunto de valores bastante grande, a menos que haya una situación extraña cuando use solo varias fechas posibles. * Editaré mi respuesta anterior para hacer una declaración más clara y válida.
Ojo