SQL se une a subconsultas de SQL (rendimiento)?

110

Deseo saber si tengo una consulta de unión algo como esto:

Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id

y una subconsulta algo como esto:

Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept)

Cuando considero el rendimiento, ¿ cuál de las dos consultas sería más rápida y por qué ?

¿También hay un momento en el que debería preferir uno sobre el otro?

Lo siento si esto es demasiado trivial y me lo preguntaron antes, pero estoy confundido. Además, sería genial si me pudieran sugerir herramientas que debería usar para medir el rendimiento de dos consultas. ¡Muchas gracias!

Vishal
fuente
5
@Lucero, esta pregunta está etiquetada como sql-server-2008, donde la publicación que mencionas está etiquetada como MySql. Puede inferir que las respuestas serán las mismas. La optimización del rendimiento se realiza de forma diferente en los dos RDBMS.
Francois Botha

Respuestas:

48

ESPERARÍA que la primera consulta sea más rápida, principalmente porque tiene una equivalencia y un JOIN explícito. En mi experiencia INes un operador muy lento, ya que SQL normalmente lo evalúa como una serie de WHEREcláusulas separadas por "OR" ( WHERE x=Y OR x=Z OR...).

Sin embargo, como con TODAS LAS COSAS SQL, su kilometraje puede variar. La velocidad dependerá mucho de los índices (¿tienes índices en ambas columnas de ID? Eso ayudará mucho ...) entre otras cosas.

La única forma REAL de saber con 100% de certeza qué es más rápido es activar el seguimiento del rendimiento (las estadísticas de IO son especialmente útiles) y ejecutar ambos. ¡Asegúrate de borrar tu caché entre ejecuciones!

JNK
fuente
16
Tengo serias dudas sobre esta respuesta, ya que la mayoría de los DBMS, definitivamente SQL Server 2008 y versiones posteriores, traducen la subconsulta de ID única (no correlacionada, es decir, no hace referencia a múltiples columnas de consulta externas) en una semi-unión relativamente rápida. Además, como se señaló anteriormente en otra respuesta, la primera combinación real devolverá una fila para CADA aparición de la ID coincidente en el Departamento; esto no hace ninguna diferencia para una ID única, pero le dará toneladas de duplicados en otros lugares. Ordenarlos con DISTINCT o GROUP BY será otra carga pesada de rendimiento. ¡Verifique los planes de ejecución en SQL Server Management Studio!
Erik Hart
2
La cláusula IN como equivalente a OR se aplica a las listas de parámetros / valores, pero no a las subconsultas, que en su mayoría se tratan como combinaciones.
Erik Hart
42

Bueno, creo que es una pregunta "vieja pero dorada". ¡La respuesta es, depende!". Las actuaciones son un tema tan delicado que sería demasiado tonto decir: "Nunca uses subconsultas, únete siempre". En los siguientes enlaces, encontrará algunas prácticas recomendadas básicas que me han resultado muy útiles:

Tengo una tabla con 50000 elementos, el resultado que buscaba eran 739 elementos.

Mi consulta al principio fue esta:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND p.anno = (
    SELECT MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p2.fixedId = p.fixedId 
)

y tardó 7,9 segundos en ejecutarse.

Mi consulta al fin es esta:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND (p.fixedId, p.anno) IN
(
    SELECT p2.fixedId, MAX(p2.anno)
    FROM prodotto p2
    WHERE p.azienda_id = p2.azienda_id
    GROUP BY p2.fixedId
)

y tomó 0.0256s

Buen SQL, bueno.

linuxatico
fuente
3
Interesante, ¿podría explicar cómo se solucionó la adición de GROUP BY?
cozos
6
La tabla temporal generada por la subconsulta era más pequeña. Por lo tanto, la ejecución es más rápida ya que hay menos datos para registrar.
Sirmyself
2
Creo que en la primera consulta ha compartido una variable entre la consulta externa y la subconsulta, por lo que para cada fila en la consulta principal, la subconsulta se ejecuta, pero en la segunda, la subconsulta solo se ejecuta una vez y de esta manera el rendimiento mejora.
Ali Faradjpour
1
Sql server y MySql y ... Sql (excepto NoSql) son muy similares en infraestructura. Tenemos una especie de motor de optimización de consultas debajo que convierte las cláusulas IN (...) en unirse (si fuera posible). Pero cuando tienes un Agrupar por en una columna bien indexada (según su cardinalidad), será mucho más rápido. Entonces realmente depende de la situación.
Alix
10

Comience a mirar los planes de ejecución para ver las diferencias en cómo los interpretará el servidor SQl. También puede usar Profiler para ejecutar las consultas varias veces y obtener la diferencia.

No esperaría que estos fueran tan horriblemente diferentes, donde puede obtener grandes ganancias de rendimiento reales al usar uniones en lugar de subconsultas cuando usa subconsultas correlacionadas.

EXISTS es a menudo mejor que cualquiera de estos dos y cuando habla de combinaciones izquierdas donde desea que todos los registros no estén en la tabla de combinación izquierda, entonces NO EXISTE suele ser una opción mucho mejor.

HLGEM
fuente
9

El rendimiento se basa en la cantidad de datos que está ejecutando ...

Si es menos datos alrededor de 20k. JOIN funciona mejor.

Si los datos son más como 100k + entonces IN funciona mejor.

Si no necesita los datos de la otra tabla, IN es bueno, pero siempre es mejor optar por EXISTS.

Todos estos criterios los probé y las tablas tienen índices adecuados.

JP Emvia
fuente
4

El rendimiento debe ser el mismo; es mucho más importante tener los índices y la agrupación en clústeres correctos aplicados en sus tablas (existen algunos buenos recursos sobre ese tema).

(Editado para reflejar la pregunta actualizada)

Lucero
fuente
4

Es posible que las dos consultas no sean semánticamente equivalentes. Si un empleado trabaja para más de un departamento (posible en la empresa para la que trabajo; es cierto, esto implicaría que su tabla no está completamente normalizada), entonces la primera consulta devolvería filas duplicadas mientras que la segunda consulta no. Para que las consultas sean equivalentes en este caso, la DISTINCTpalabra clave debería agregarse a la SELECTcláusula, lo que puede tener un impacto en el rendimiento.

Tenga en cuenta que hay una regla de diseño que establece que una tabla debe modelar una entidad / clase o una relación entre entidades / clases, pero no ambas. Por lo tanto, le sugiero que cree una tercera tabla, digamos OrgChart, para modelar la relación entre empleados y departamentos.

un día cuando
fuente
4

Sé que esta es una publicación antigua, pero creo que es un tema muy importante, especialmente hoy en día, donde tenemos más de 10 millones de registros y hablamos de terabytes de datos.

También contribuiré con las siguientes observaciones. Tengo alrededor de 45 millones de registros en mi tabla ([datos]) y alrededor de 300 registros en mi tabla [gatos]. Tengo una indexación extensa para todas las consultas de las que estoy a punto de hablar.

Considere el ejemplo 1:

UPDATE d set category = c.categoryname
FROM [data] d
JOIN [cats] c on c.id = d.catid

versus Ejemplo 2:

UPDATE d set category = (SELECT TOP(1) c.categoryname FROM [cats] c where c.id = d.catid)
FROM [data] d

El ejemplo 1 tardó unos 23 minutos en ejecutarse. El ejemplo 2 tomó alrededor de 5 minutos.

Entonces, concluiría que la subconsulta en este caso es mucho más rápida. Por supuesto, tenga en cuenta que estoy usando unidades SSD M.2 con capacidad de E / S a 1 GB / seg (eso es bytes, no bits), por lo que mis índices también son muy rápidos. Entonces, esto también puede afectar las velocidades en sus circunstancias

Si se trata de una limpieza de datos única, probablemente sea mejor dejarla ejecutándose y finalizar. Utilizo TOP (10000) y veo cuánto tiempo lleva y multiplico por el número de registros antes de llegar a la gran consulta.

Si está optimizando las bases de datos de producción, le sugiero encarecidamente que procese previamente los datos, es decir, utilice activadores o intermediarios de trabajo para sincronizar los registros de actualización, de modo que el acceso en tiempo real recupere datos estáticos.

Arvin Amir
fuente
0

Puede utilizar un plan de explicación para obtener una respuesta objetiva.

Para su problema, un filtro Exists probablemente funcionaría más rápido.

Snekse
fuente
2
"Un filtro Exists probablemente funcionaría más rápido" - probablemente no, creo, aunque una respuesta definitiva requeriría probar con los datos reales. Es probable que los filtros existentes sean más rápidos cuando hay varias filas con los mismos valores de búsqueda, por lo que un filtro existente podría ejecutarse más rápido si la consulta verificaba si se habían registrado otros empleados del mismo departamento, pero probablemente no cuando se compara con un departamento. mesa.
¿Funcionaría más lento en ese último escenario?
Snekse
Dependería del optimizador; en determinadas circunstancias, podría hacerlo, pero normalmente esperaría un rendimiento muy similar.