¿Existe una diferencia de ejecución entre una condición JOIN y una condición WHERE?

17

¿Existe una diferencia de rendimiento entre estas dos consultas de ejemplo?

Consulta 1:

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y'

Consulta 2;

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
   and b.tag = 'Y'

Observe que la única diferencia es la ubicación de la condición suplementaria; el primero usa una WHEREcláusula y el segundo agrega la condición a la ONcláusula.

Cuando ejecuto estas consultas en mi sistema Teradata, los planes de explicación son idénticos y el paso UNIR muestra la condición adicional en cada caso. Sin embargo, en esta pregunta SO con respecto a MySQL, una de las respuestas sugirió que se prefiere el segundo estilo porque el WHEREprocesamiento ocurre después de que se realizan las uniones.

¿Hay una regla general a seguir al codificar consultas como esta? Supongo que debe depender de la plataforma, ya que obviamente no hace ninguna diferencia en mi base de datos, pero tal vez eso sea solo una característica de Teradata. Y si es dependiente de la plataforma, me gustaría mucho conseguir algunas referencias de documentación; Realmente no sé qué buscar.

BellevueBob
fuente
9
Depende de la plataforma, ya que depende de cómo el optimizador RDBMS trata con el análisis y la optimización.
Philᵀᴹ
8
Y esa respuesta en la pregunta vinculada merece varios votos negativos. Incluso el optimizador primitivo de MySQL entendería que estas consultas simples son equivalentes y que "la cláusula WHERE se evalúa después de que se hayan realizado todas las uniones" es verdadera solo en un nivel lógico, no en la ejecución real.
ypercubeᵀᴹ
1
No es realmente un duplicado; esa pregunta y las respuestas estaban comparando la sintaxis "implícita" versus "explícita" JOIN Estoy preguntando específicamente sobre condiciones de unión suplementarias.
BellevueBob
No me atreveré a publicar una respuesta ya que lo intenté antes y obtuve muchos votos negativos. Cuando hay muchas uniones, tengo casos de experiencia de traer la condición a la unión que resultó en un mejor plan de consulta (se filtró temprano). Sigue siendo el mismo resultado.
paparazzo

Respuestas:

14

De acuerdo con el Capítulo 9 (Analizador y Optimizador), Página 172 del Libro Comprensión de MySQL Internals por Sasha Pachev

Comprender los aspectos internos de MySQL

Aquí está el desglose de la evaluación de una consulta como las siguientes tareas:

  • Determine qué claves se pueden usar para recuperar los registros de las tablas y elija la mejor para cada tabla.
  • Para cada tabla, decida si una exploración de tabla es mejor que leer en una clave. Si hay muchos registros que coinciden con el valor de la clave, las ventajas de la clave se reducen y el escaneo de la tabla se vuelve más rápido.
  • Determine el orden en el que se deben unir las tablas cuando hay más de una tabla presente en la consulta.
  • Vuelva a escribir las cláusulas WHERE para eliminar el código muerto, reduciendo los cálculos innecesarios y cambiando las restricciones siempre que sea posible para abrir el camino para el uso de claves.
  • Elimine las tablas no utilizadas de la unión.
  • Determine si las teclas se pueden usar para ORDER BYy GROUP BY.
  • Intente simplificar las subconsultas y determine en qué medida se pueden almacenar en caché sus resultados.
  • Combinar vistas (expanda la referencia de vista como una macro)

En esa misma página, dice lo siguiente:

En la terminología del optimizador MySQL, cada consulta es un conjunto de combinaciones. El término join se usa aquí más ampliamente que en los comandos SQL. Una consulta en una sola tabla es una unión degenerada. Si bien normalmente no pensamos en leer registros de una tabla como una combinación, las mismas estructuras y algoritmos utilizados con las combinaciones convencionales funcionan perfectamente para resolver la consulta con una sola tabla.

EPÍLOGO

Debido a las claves presentes, la cantidad de datos y la expresión de la consulta, MySQL Joins a veces puede hacer cosas por nuestro propio bien (o para responder a nosotros) y obtener resultados que no esperábamos y que no podemos explicar rápidamente.

Escribí sobre esta peculiaridad antes

porque MySQL Query Optimizer podría hacer que se descarten ciertas claves durante la evaluación de la consulta.

El comentario de @ Phil me ayudó a ver cómo publicar esta respuesta (+1 para el comentario de @ Phil)

El comentario de @ypercube (+1 para este también) es una versión compacta de mi publicación porque el Optimizador de consultas de MySQL es primitivo. Desafortunadamente, tiene que ser ya que se trata de motores de almacenamiento externos.

CONCLUSIÓN

En cuanto a su pregunta real, MySQL Query Optimizer determinaría las métricas de rendimiento de cada consulta cuando se realice.

  • contando filas
  • seleccionando teclas
  • masajear conjuntos de resultados intermitentes
  • Oh sí, haciendo la UNIÓN real

Probablemente tendría que forzar el orden de ejecución reescribiendo (refactorizando) la consulta

Aquí está la primera consulta que diste

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y';

Intente reescribirlo para evaluar el DÓNDE primero

select count(*)
from   table1 a
join   (select key_col from table2 where tag='Y') b
on     b.key_col=a.key_col;

Eso definitivamente alteraría el plan EXPLICAR. Podría producir mejores o peores resultados.

Una vez respondí una pregunta en StackOverflow donde apliqué esta técnica. El EXPLICAR fue horrendo pero el rendimiento fue dinamita. Solo funcionó por tener los índices correctos presentes y el uso de LIMIT en una subconsulta .

Al igual que con los precios de las acciones, cuando se trata de consultas e intentar expresarlas, se aplican restricciones, los resultados pueden variar y el rendimiento pasado no es indicativo de resultados futuros.

RolandoMySQLDBA
fuente
2
¡+1 para la información detallada específica de MySQL y especialmente para engañarme para que aprenda la diferencia entre "Epílogo" y "Conclusión"!
BellevueBob
En mi publicación, el epílogo es una conclusión secundaria.
RolandoMySQLDBA
66
@Rolando: Puede agregar una Secuela sobre las mejoras en los optimizadores en las últimas versiones de MariaDB (5.3 y 5.5) y en la versión principal de MySQL (5.6) recientemente lanzada. Lo que puede hacer que alguna reescritura sea innecesaria.
ypercubeᵀᴹ
1

Para Oracle, dado que mySQL tenía una descripción extensa, tenemos 2 formas de alto nivel de aprovechar el optimizador.

Primero es la optimización basada en reglas (o RBO). Oracle tiene 15 reglas establecidas que cada consulta que analiza intenta seguir en un orden establecido. Si no puede generar una consulta optimizada a partir de la regla 1, avanzará a la regla 2 y avanzará hasta que llegue a la regla 15.

Para más información: https://docs.oracle.com/cd/B10500_01/server.920/a96533/rbo.htm

Estos afectan a los núcleos Oracle RDBMS de 11.1 e inferiores que no se han convertido al Optimizador basado en costos (también conocido como CBO). Oracle 11.2 y versiones posteriores requieren el optimizador CBO, pero pueden forzar la identificación específica de SQL para optimizar en el antiguo método RBO si el usuario lo desea.

El CBO para Oracle 11.1+ en su lugar hace varios planes de ejecución para la misma ID de SQL y ejecuta el que tiene el menor costo total previsto. Aprovecha gran parte de la lógica de RBO, pero analiza las estadísticas de la tabla para crear costos de planes de ejecución dinámicos para cada operación que la base de datos tiene que hacer para proporcionar sus datos al usuario final. Ejecutar escaneos completos de tablas en tablas muy grandes es realmente costoso; Ejecutar escaneos completos de tablas en una tabla con 10 filas es barato. En RBO, estas se consideraron operaciones iguales.

Para más información: https://oracle-base.com/articles/misc/cost-based-optimizer-and-database-statistics

Para su ejemplo de consulta específica: es probable que Oracle analice la información para hacer diferentes planes de ejecución y, por lo tanto, uno será técnicamente mejor que el otro. Sin embargo, esto puede ser una diferencia mínima. Al observarlo, tanto Oracle RBO como CBO desearían consultar 1 más porque se ejecuta en una unión en menos condiciones y luego filtra una columna específica de la tabla temporal que hizo desde la unión.

JB-Learner
fuente
1

Si tiene dos consultas y cree que son equivalentes, puede ocurrir lo siguiente:

  1. Ambas consultas tienen el mismo plan de ejecución. Eso está bien y eso es lo que esperamos. Esperemos que sea el plan de ejecución óptimo para la consulta.
  2. Existen diferentes planes de ejecución. Tenemos dos subcajas aquí.

    2.1 Las consultas tienen diferentes planes de ejecución, pero ambos planes funcionan igual de bien. Eso también está bien. No es necesario que para consultas equivalentes se genere el mismo plan. Pero el rendimiento debe ser igual. Y de nuevo esperamos que sea lo mejor posible.

    2.2 Las consultas tienen diferentes planes de ejecución y un plan es mejor que el otro. Nuevamente tenemos subcasas:

    2.2.1 Los planes son diferentes porque las consultas no son equivalentes. Por lo tanto, compruebe cuidadosamente si son realmente equivalentes. En tu caso son realmente equivalentes.

    2.2.2 Los planes son diferentes pero las consultas son equivalentes. Esto significa que el optimizador no ha madurado lo suficiente. En un mundo perfecto con optimizadores perfectos, esto no debería suceder. Entonces, sí, depende de la plataforma y debe estudiar documentos específicos de la plataforma para descubrir por qué sucede esto.

    2.2.3 Los planes son diferentes, las consultas son equivalentes, el software de la base de datos tiene un error.

milagro173
fuente