Subconsultas vs uniones

158

Refactoré una sección lenta de una aplicación que heredamos de otra compañía para usar una combinación interna en lugar de una subconsulta como:

WHERE id IN (SELECT id FROM ...)

La consulta refactorizada se ejecuta aproximadamente 100 veces más rápido. (~ 50 segundos a ~ 0.3) Esperaba una mejora, pero ¿alguien puede explicar por qué fue tan drástico? Las columnas utilizadas en la cláusula where fueron indexadas. ¿SQL ejecuta la consulta en la cláusula where una vez por fila o algo así?

Actualización - Explicar los resultados:

La diferencia está en la segunda parte de la consulta "where id in ()":

2   DEPENDENT SUBQUERY  submission_tags ref st_tag_id   st_tag_id   4   const   2966    Using where

vs 1 fila indexada con la unión:

    SIMPLE  s   eq_ref  PRIMARY PRIMARY 4   newsladder_production.st.submission_id  1   Using index
palmsey
fuente
44
Posible duplicado de Join vs.
subconsulta
2
No es un duplicado Esta pregunta es específicamente sobre la notable diferencia de rendimiento. La otra pregunta es más general, abierta sobre los pros y los contras de cada enfoque y por qué un enfoque parece más popular.
Basil Bourque
@simhumileco Eso no es una mejora, no hay diferencia, es contrario a lo que escribió el autor y ese tipo de edición para el estilo de código es inapropiado. ¿Cuándo debo hacer modificaciones al código?
philipxy
Hola @philipxy, no tenía la intención de interferir en el pensamiento del autor, sino solo hacer que el fragmento de código fuera más legible y escrito con más cuidado.
simhumileco

Respuestas:

160

Una "subconsulta correlacionada" (es decir, una en la que la condición where depende de los valores obtenidos de las filas de la consulta que contiene) se ejecutará una vez para cada fila. Una subconsulta no correlacionada (una en la que la condición where es independiente de la consulta que lo contiene) se ejecutará una vez al principio. El motor SQL hace esta distinción automáticamente.

Pero sí, explicar-plan te dará los detalles sucios.

Jeffrey L Whitledge
fuente
3
Tenga en cuenta que DEPENDENT SUBQUERYsignifica exactamente lo mismo que "subconsulta correlacionada".
Timo
38

Está ejecutando la subconsulta una vez por cada fila, mientras que la unión ocurre en los índices.

Sklivvz
fuente
55
No creo que esto sea cierto. El motor SQL debe ejecutar la subconsulta solo una vez y usar el resultado como una lista.
Dacracot
8
Eso depende: si la subconsulta se correlaciona de alguna manera con la consulta externa (usa sus datos), se ejecuta con cada fila.
qbeuek
44
Probablemente sea cierto en este caso, pero no es cierto en general.
Amy B
1
OP EXPLAINdice DEPENDENT SUBQUERY, que es el indicador más claro de este comportamiento.
Timo
16

Aquí hay un ejemplo de cómo se evalúan las subconsultas en MySQL 6.0 .

El nuevo optimizador convertirá este tipo de subconsultas en combinaciones.

Giuseppe Maxia
fuente
Ese es un gran artículo sobre el optimizador mejorado MySQL 6.0, gracias
Fire Crow
7

Ejecute el plan de explicación en cada versión, le dirá por qué.

escocia
fuente
6

antes de que las consultas se ejecuten en el conjunto de datos, se someten a un optimizador de consultas, el optimizador intenta organizar la consulta de tal manera que pueda eliminar tantas tuplas (filas) del conjunto de resultados lo más rápido posible. A menudo, cuando utiliza subconsultas (especialmente las malas), las tuplas no pueden eliminarse del conjunto de resultados hasta que la consulta externa comience a ejecutarse.

Sin ver la consulta, es difícil decir qué tenía de malo el original, pero supongo que fue algo que el optimizador no pudo mejorar mucho. Ejecutar 'explicar' le mostrará el método de optimizadores para recuperar los datos.

pfranza
fuente
4

Mire el plan de consulta para cada consulta.

¿En qué lugar y Únete puede normalmente ser implementado usando el mismo plan de ejecución, por lo que normalmente no es cero aceleración de cambiar entre ellos.

Amy B
fuente
3
Jaja, I <3 Sql elimina ese voto negativo porque no saben cómo leer los planes de consulta.
Amy B
4

Optimizer no hizo un muy buen trabajo. Por lo general, se pueden transformar sin ninguna diferencia y el optimizador puede hacer esto.

Cade Roux
fuente
4

Por lo general, es el resultado de que el optimizador no puede darse cuenta de que la subconsulta puede ejecutarse como una combinación, en cuyo caso ejecuta la subconsulta para cada registro en la tabla en lugar de unir la tabla en la subconsulta contra la tabla que está consultando. Algunas de las bases de datos más "empresariales" son mejores en esto, pero a veces aún lo echan de menos.

Mark Roddy
fuente
4

Esta pregunta es algo general, así que aquí hay una respuesta general:

Básicamente, las consultas tardan más cuando MySQL tiene toneladas de filas para ordenar.

Hacer esto:

Ejecute un EXPLICAR en cada una de las consultas (la UNIDA, luego la Subconsulta), y publique los resultados aquí.

Creo que ver la diferencia en la interpretación de MySQL de esas consultas sería una experiencia de aprendizaje para todos.

Pete Karl II
fuente
4

La subconsulta where tiene que ejecutar 1 consulta por cada fila devuelta. La unión interna solo tiene que ejecutar 1 consulta.

Shawn
fuente
3

La subconsulta probablemente estaba ejecutando una "exploración de tabla completa". En otras palabras, no usar el índice y devolver demasiadas filas que el Where de la consulta principal necesitaba filtrar.

Solo una suposición sin detalles, por supuesto, pero esa es la situación común.

igelkott
fuente
2

Con una subconsulta, debe volver a ejecutar el segundo SELECCIONAR para cada resultado, y cada ejecución generalmente devuelve 1 fila.

Con una unión, la 2da SELECCIÓN devuelve muchas más filas, pero solo tiene que ejecutarla una vez. La ventaja es que ahora puede unirse a los resultados, y unir relaciones es en lo que se supone que una base de datos es buena. Por ejemplo, quizás el optimizador pueda detectar cómo aprovechar mejor un índice ahora.

Joel Coehoorn
fuente
2

No es tanto la subconsulta como la cláusula IN, aunque las uniones son la base de al menos el motor SQL de Oracle y se ejecutan extremadamente rápido.

dacracot
fuente
1
donde realmente no es inherentemente malo.
Shawn
2

Tomado del Manual de referencia ( 14.2.10.11 Reescritura de subconsultas como uniones ):

Una IZQUIERDA [EXTERIOR] IZQUIERDA puede ser más rápida que una subconsulta equivalente porque el servidor podría optimizarla mejor, un hecho que no es específico solo del servidor MySQL.

Por lo tanto, las subconsultas pueden ser más lentas que las de IZQUIERDA [EXTERIOR].

simhumileco
fuente