2010-07-01 8 views
9

Digamos que tenemos dos tablas: 'coche' y 'parte', con una mesa de unirse en 'Car_Part'. Supongamos que quiero ver todos los automóviles que tienen una parte 123 en ellos. Yo podría hacer esto:¿Qué es más rápido: ÚNASE con GROUP BY o una subconsulta?

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
INNER JOIN Car_Part ON Car_Part.Car_Id = Car.Car_Id 
WHERE Car_Part.Part_Id = @part_to_look_for 
GROUP BY Car.Col1, Car.Col2, Car.Col3 

O podría hacer esto

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE Car.Car_Id IN (SELECT Car_Id FROM Car_Part WHERE Part_Id = @part_to_look_for) 

Ahora, todo en mí quiere usar el primer método, ya que he sido educado por los buenos padres que me inculcaron una odio puritano de subconsultas y amor por la teoría de conjuntos, pero se me ha sugerido que hacer ese gran GRUPO BY es peor que una subconsulta.

Debo señalar que estamos en SQL Server 2008. También debo decir que en realidad quiero seleccionar en base al ID de la franja, Parte Tipo y posiblemente otras cosas también. Por lo tanto, la consulta que quiero hacer en realidad se parece a esto:

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
INNER JOIN Car_Part ON Car_Part.Car_Id = Car.Car_Id 
INNER JOIN Part ON Part.Part_Id = Car_Part.Part_Id 
WHERE (@part_Id IS NULL OR Car_Part.Part_Id = @part_Id) 
AND (@part_type IS NULL OR Part.Part_Type = @part_type) 
GROUP BY Car.Col1, Car.Col2, Car.Col3 

O ...

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE (@part_Id IS NULL OR Car.Car_Id IN (
    SELECT Car_Id 
    FROM Car_Part 
    WHERE Part_Id = @part_Id)) 
AND (@part_type IS NULL OR Car.Car_Id IN (
    SELECT Car_Id 
    FROM Car_Part 
    INNER JOIN Part ON Part.Part_Id = Car_Part.Part_Id 
    WHERE Part.Part_Type = @part_type)) 
+2

¿Has ejecutado ambos? Miró los planes de consulta? Benchmarked? – Oded

+1

Tendría que generar una gran cantidad de datos, por lo que no lo resolveré hasta la próxima semana. Y cuando buscaba una respuesta en Google, no encontré ninguna, así que vale la pena publicar una pregunta en línea para cualquier otra persona que pueda estar buscando. – d4nt

+0

Agrupar por es un trabajo intensivo, que se usa para calcular cosas como promedios, sumas, etc. Pareces usarlo para eliminar duplicados. Pruebe DISTINCT sin el grupo por ... – Alocyte

Respuesta

3

que tienen datos similares por lo que he comprobado el plan de ejecución de ambos estilos de consulta. Para mi sorpresa, Column In Subquery (CIS) produjo un plan de ejecución con un 25% menos de costo de I/O que la consulta de combinación interna (IJ). En el plan de ejecución de CIS, obtengo 2 escaneos de índice de la tabla intermedia (Car_Part) versus un escaneo de índice del intermediario y una combinación de compilación relativamente más costosa en el IJ. Mis índices son saludables pero no agrupados, por lo que es lógico pensar que los escaneos de índice podrían hacerse un poco más rápidos al agruparlos. Dudo que esto afecte el costo de la combinación de hash, que es el paso más costoso en la consulta de IJ.

Al igual que los otros han señalado, que depende de sus datos. Si trabajas con muchos gigabytes en estas 3 tablas, entonces sintoniza. Si sus filas están numeradas en cientos o en miles, es posible que esté dividiendo cabellos sobre una ganancia de rendimiento muy pequeña. Diría que la consulta de IJ es mucho más legible, por lo que siempre que sea lo suficientemente bueno, haga un favor a cualquier futuro desarrollador que toque su código y deles algo más fácil de leer. El recuento de filas en mis tablas es 188877, 283912, 13054 y ambas consultas se devolvieron en menos tiempo de lo que tardó en sorber café.

Postdata pequeña: como no está agregando ningún valor numérico, parece que quiere seleccionar distinto. A menos que realmente vaya a hacer algo con el grupo, es más fácil ver su intención con seleccionar distintas en lugar de agruparlas al final.El costo de IO es el mismo, pero uno indica su intención en mi humilde opinión.

4

Lo mejor que puede hacer es que probarse a sí mismo, en volúmenes de datos realistas. Eso no solo sería beneficioso para esta consulta, sino para todas las consultas futuras cuando no esté seguro de cuál es la mejor manera.

cosas importantes que hacer incluyen:
- prueba en volúmenes de datos a nivel de la producción
- prueba bastante & consistentemente (borrar la memoria caché: http://www.adathedev.co.uk/2010/02/would-you-like-sql-cache-with-that.html)
- verificar el plan de ejecución

Usted podría monitor utilizando el Analizador de SQL y compruebe la duración/lecturas/escrituras/CPU allí, o SET STATISTICS IO ON; SET STATISTICS TIME ON; para generar estadísticas en SSMS. Luego compara las estadísticas para cada consulta.

Si no se puede hacer este tipo de pruebas, podrás potencialmente exponerse a problemas de rendimiento en la línea que tendrá que luego sintonice/rectificar. Hay herramientas que puedes usar que generarán datos para ti.

2

Con SQL Server 2008 esperaría que In fuera más rápido ya que es equivalente a esto.

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE EXISTS(SELECT * FROM Car_Part 
      WHERE Car_Part.Car_Id = Car.Car_Id 
      AND Car_Part.Part_Id = @part_to_look_for 
) 

es decir, solo tiene que comprobar la existencia de la fila no unirla y luego eliminar los duplicados. Esto es discussed here.

Cuestiones relacionadas