2010-10-04 17 views
72

Me gustaría saber si tengo una unen consulta algo como esto -SQL se une a las subconsultas de SQL (rendimiento)?

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 rendimiento cuál de las dos consultas serían más rápidas y ¿por qué?

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

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

+3

Vea también http://stackoverflow.com/questions/2577174/sql-join-vs-subquery – Lucero

+3

@Lucero, esta pregunta está etiquetada como sql-server-2008, donde la publicación que menciona está etiquetada como MySql. Puedes deducir que las respuestas serán las mismas. La optimización del rendimiento se realiza de forma diferente en los dos RDBMS. –

Respuesta

36

Yo esperaría que la primera consulta sea más rápido, sobre todo porque tiene una equivalencia y unirse a un explícito. En mi experiencia IN es un operador muy lento, ya que SQL normalmente lo evalúa como una serie de cláusulas WHERE separadas por "O" (WHERE x=Y OR x=Z OR...).

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

La única forma VERDADERA de saber con 100% de certeza que es más rápida es activar el seguimiento del rendimiento (IO Statistics es especialmente útil) y ejecutarlos ambos. ¡Asegúrate de borrar tu caché entre ejecuciones!

+9

Tengo serias dudas sobre esta respuesta, ya que la mayoría de los DBMS, definitivamente SQL Server 2008 y posterior, traducen la única subconsulta de ID (no correlacionada, es decir, sin hacer referencia a múltiples columnas externas de consulta) en una semi-unión relativamente rápida.Además, como se indicó anteriormente en otra respuesta, la primera unión real devolverá una fila por 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 otro lugar. Ordenarlos con DISTINCT o GROUP BY será otra carga de alto rendimiento. ¡Verifique los planes de ejecución en SQL Server Management Studio! –

+1

La cláusula IN como equivalente a O se aplica a las listas de parámetros/valores, pero no a las subconsultas, que en su mayoría se tratan como uniones. –

2

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

(editado para reflejar la cuestión actualizada)

+0

He actualizado mi pregunta para cambiar las consultas poco ... gracias por su respuesta. – Vishal

0

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

Para su problema, an Exists filter probablemente realice el más rápido.

+2

"un filtro Exists probablemente funcionaría más rápido" - probablemente no, creo, aunque una respuesta definitiva requeriría pruebas contra 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 verificara si otros empleados se grabaron desde el mismo departamento, pero probablemente no al buscar un departamento mesa. –

+0

¿Sería más lento en ese último escenario? – Snekse

+0

Dependería del optimizador; bajo ciertas circunstancias, podría hacerlo, pero normalmente esperaría un rendimiento muy similar. –

9

Comience a ver los planes de ejecución para ver las diferencias en la forma en que el servidor SQl los interpretará. 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 aumentos de rendimiento reales al usar uniones en lugar de subconsultas es cuando usa subconsultas correlacionadas.

EXISTS es a menudo mejor que cualquiera de estos dos y cuando está hablando de uniones izquierda donde desea todos los registros que no están en la tabla de unión izquierda, entonces NO EXISTE es a menudo una opción mucho mejor.

3

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

Nota: 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 los empleados y los departamentos.

4

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

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

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

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

Todos estos criterios los he probado y las tablas tienen los índices adecuados.

22

Bueno, creo que es una pregunta "vieja pero oro". ¡La respuesta es, depende!". Las actuaciones son un tema tan delicado que sería demasiado tonto decir: "Nunca uses subconsultas, siempre únete". En los siguientes enlaces, podrás encontrar algunas de las mejores prácticas básicas que he encontrado para ser muy útil: Here 1 Here 2 Here 3

Tengo una tabla con 50000 elementos, el resultado que estaba buscando era 739 elementos .

Mi consulta en un primer momento fue la siguiente:

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.9s a ejecutar.

Mi consulta al fin es la siguiente:

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

Buena SQL, buena.

+0

Interesante, ¿podría explicarnos cómo agregar el GROUP BY lo arregló? – cozos

-1

La consulta final incluyó azienda_id en la subconsulta corelada, pero su consulta inicial no incluyó azienda_id en la subconsulta corelated. Entonces la comparación no es lo mismo.

+0

Esto debería ser un comentario sobre la respuesta de linuxatico. – jojonas

-1

He probado la teoría de HLGEM comparando los números de 'estadísticas de clientes de uso', resulta que no existe es tan rápido que se unió a la izquierda al buscar todos los registros que no están en la tabla de la izquierda.

La belleza de SQL son sus muchas formas de escribirlo, y el rendimiento no depende únicamente de la unión o subconsulta, sino del conjunto de resultados que está buscando.