2009-07-24 17 views
15

Como ejemplo, quiero obtener la lista de todos los elementos con ciertas etiquetas aplicadas. Que podía hacer cualquiera de los siguientes:SQL Efficiency: WHERE IN Subconsulta vs. JOIN luego GROUP

SELECT Item.ID, Item.Name 
FROM Item 
WHERE Item.ID IN (
    SELECT ItemTag.ItemID 
    FROM ItemTag 
    WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55) 

O

SELECT Item.ID, Item.Name 
FROM Item 
LEFT JOIN ItemTag ON ItemTag.ItemID = Item.ID 
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 
GROUP BY Item.ID, Item.Name 

o algo completamente diferente.

En general (suponiendo que exista una regla general), ¿cuál es un enfoque más eficiente?

+0

@Larsenal: puede reemplazar un 'LEFT JOIN' con un' INNER JOIN' en su segunda consulta, los resultados serán los mismos. Un 'LEFT JOIN' devolverá' NULL's para las filas en 'ItemTag' que no tienen un' Item.ID' correspondiente, y su condición 'WHERE' las filtrará. – Quassnoi

Respuesta

15
SELECT Item.ID, Item.Name 
FROM Item 
WHERE Item.ID IN (
    SELECT ItemTag.ItemID 
    FROM ItemTag 
    WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55) 

o

SELECT Item.ID, Item.Name 
FROM Item 
LEFT JOIN ItemTag ON ItemTag.ItemID = Item.ID 
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 
GROUP BY Item.ID 

Su segunda consulta no se compilará, ya que hace referencia a Item.Name sin que ninguna agrupación o agregación en él.

Si eliminamos GROUP BY de la consulta:

SELECT Item.ID, Item.Name 
FROM Item 
JOIN ItemTag 
ON  ItemTag.ItemID = Item.ID 
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 

éstos siguen siendo diferentes consultas, a menos que ItemTag.ItemId es una clave UNIQUE y marcados como tales.

SQL Server es capaz de detectar una condición de IN en una columna UNIQUE, y se acaba de transformar la condición IN en un JOIN.

Si no es ItemTag.ItemIDUNIQUE, la primera consulta utilizará un tipo de un algoritmo SEMI JOIN, que son bastante eficientes en SQL Server.

Usted puede trasform la segunda consulta en una JOIN:

SELECT Item.ID, Item.Name 
FROM Item 
JOIN (
     SELECT DISTINCT ItemID 
     FROMT ItemTag 
     WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 
     ) tags 
ON  tags.ItemID = Item.ID 

pero éste es un poco menos eficiente que IN o EXISTS.

Lee este artículo en mi blog para una comparación más detallada de rendimiento:

4

Creo que dependerá de cómo maneje el optimizador, incluso puede ser que acabe teniendo el mismo rendimiento. Mostrar plan de ejecución es tu amigo aquí.

1

Es casi imposible (a menos que seas uno de esos DBA gurú loco) decir lo que será rápido y lo que no será sin mirar el plan de ejecución y/o ejecutar algunas pruebas de estrés.

+2

De hecho, es fácil de decir: el segundo es mucho más rápido. Simplemente se negará a compilar en un nanosegundo más o menos. – Quassnoi

+0

Creo que lo arreglé ahora. – Larsenal

+2

@Quassnoi ¿Eso no lo haría más lento? Se necesita una cantidad de tiempo infinita para devolver el resultado ... – Kasapo

2
SELECT Item.ID, Item.Name 
... 
GROUP BY Item.ID 

Esto no es válido T-SQL. Item.Name debe aparecer en la cláusula group by o dentro de una función agregada, como SUM o MAX.

+0

Gracias. Lo he arreglado – Larsenal

0

plazo esto:

SET SHOWPLAN_ALL ON 

continuación, ejecute cada versión de la consulta

se puede ver si regresan el mismo plan, y si no mirar el TotalSubtreeCost en la primera fila de cada uno y ver qué tan diferentes son.

0

Rendimiento siempre parece conseguir el voto, pero también se oye "es más barato que comprar hardware de programadores "

El segundo gana en rendimiento.

A veces es bueno mirar SQL y conocer el propósito, pero para eso sirven los comentarios. La primera consulta está usando la otra tabla para un filtro, bastante sencillo.

El segundo tendría más sentido (desde un punto de vista comprensivo y no de rendimiento) usando distinct en lugar de group by. Esperaría que algunos agregados estuvieran en el select, pero no hay ninguno. La velocidad mata.

0

El segundo es más eficiente en MySQL. MySQL volverá a ejecutar la consulta dentro de la instrucción IN para cada prueba de condición WHERE.

Cuestiones relacionadas