2012-04-24 10 views
39

Suponiendo que tengo el siguiente código de T-SQL:cláusula WHERE vs ON cuando utilice JOIN

SELECT * FROM Foo f 
INNER JOIN Bar b ON b.BarId = f.BarId; 
WHERE b.IsApproved = 1; 

La siguiente también se devuelve el mismo conjunto de filas:

SELECT * FROM Foo f 
INNER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId); 

Esto no podría ser la mejor muestra de caso aquí, pero ¿hay alguna diferencia de rendimiento entre estos dos?

+2

Aquí hay una pregunta similar: http://stackoverflow.com/questions/2509987/which-sql-query-is-faster-filter-on-join-criteria-or-where-clause –

+11

La máquina lo resolverá y optimizarlo adecuadamente Sin embargo, para los humanos que necesitarán depurar \ modificar \ apoyar su código en años a partir de ahora, mantenga las condiciones de filtrado en 'DONDE' y condiciones de unión en 'ENCENDIDO'. –

+0

@KM. No siempre sé cómo diferenciar qué es una condición de unión y qué es un filtro. Por ejemplo [en esta respuesta] (http://stackoverflow.com/a/9303069/119477) Creo que es mejor en la unión, entonces ¿es una "condición de unión"? [Aquí hay otro ejemplo] (http://stackoverflow.com/a/6473403/119477) que ni siquiera sé cómo volver a escribir la cláusula where equivalente. –

Respuesta

28

No, el optimizador de consultas es lo suficientemente inteligente como para elegir el mismo plan de ejecución para ambos ejemplos.

Puede usar SHOWPLAN para verificar el plan de ejecución.


Sin embargo, usted debe poner todos se unen conexión en la cláusula ON y todas las restricciones sobre la cláusula WHERE.

+2

Pásamelo. Aunque como una cuestión de preferencia, me gustaría ir con el JOIN ya que es más descriptivo. – Ste

+1

Gracias! Imagine una situación con 7 u 8 INGRESOS INTERNOS. ¿Tu respuesta también es aplicable a esas situaciones? – tugberk

+13

@Ste IMO, en realidad es más confuso poner todo en 'JOIN'. Use 'JOIN' para relacionarse con tablas en una consulta. Use 'WHERE' para filtrar los resultados. Es cuando mezclas los dos y usas ** solo ** uno o el otro para que las consultas se vuelvan difíciles de leer. – Yuck

5
SELECT * FROM Foo f 
INNER JOIN Bar b ON b.BarId = f.BarId 
WHERE b.IsApproved = 1; 

Esta es la mejor forma de proceder. Es fácil de leer y fácil de modificar. En el mundo de los negocios, esto es lo que te gustaría hacer. En cuanto al rendimiento, son los mismos sin embargo.

+0

En mi situación actual, estoy a favor de la cláusula WHERE, pero no pude evitar preguntarme si hay una diferencia de rendimiento. ¡Gracias! – tugberk

42

Solo tenga cuidado con la diferencia con las uniones externas. Una consulta donde se añade un filtro de b.IsApproved (en la tabla de la derecha, Bar) a la ON condición del JOIN:

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId); 

Es NO lo mismo que colocar el filtro en el WHERE cláusula:

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId) 
WHERE (b.IsApproved = 1); 

Dado que para 'fracasado' exterior se une a Bar (es decir, donde no hay b.BarId para un f.BarId), esto dejará b.IsApproved como NULL para todos tales fa iled join rows, y estas filas serán filtradas.

Otra forma de ver esto es que para la primera consulta, LEFT OUTER JOIN Bar b ON (b.IsApproved = 1) AND (b.BarId = f.BarId) siempre devolverá las filas de la tabla IZQUIERDA, ya que LEFT OUTER JOIN garantiza que las filas de la tabla IZQUIERDA se devolverán incluso si la unión falla. Sin embargo, el efecto de agregar (b.IsApproved = 1) a la condición LEFT OUTER JOIN es anular las columnas de la tabla derecha cuando (b.IsApproved = 1) es falso, es decir, según las mismas reglas que se aplican normalmente a una condición LEFT JOIN en (b.BarId = f.BarId).

actualización: Para completar la pregunta hecha por Conrad, la LOJ equivalente para un filtro opcional sería:

SELECT * 
FROM Foo f 
LEFT OUTER JOIN Bar b ON (b.BarId = f.BarId) 
WHERE (b.IsApproved IS NULL OR b.IsApproved = 1); 

es decir El WHERE cláusula debe tener en cuenta tanto la condición de si la unión falla (NULL) y el filtro se debe ignorar, y donde la unión tiene éxito y se debe aplicar el filtro.(b.IsApproved o b.BarId podrían ser probados para NULL)

He puesto un SqlFiddle together here que demuestra las diferencias entre las diversas ubicaciones de la b.IsApproved filtro con relación a la JOIN.

+0

+1, buen punto! –

+0

Muy buen punto. Si coloca los datos de prueba de criterios de filtro de una combinación externa en la unión externa, obtendrá más filas de las esperadas, ya que se devolverán todos los Foos independientemente del estado o existencia de la barra. Cuando el filtrado se especifica por separado de la unión, primero se unen las filas de las dos tablas, y luego el filtro elimina la fila completa de la tabla donde no se cumplen los criterios. – KeithS

+1

@nonnb Ok, pero si corrigió la cláusula WHERE en la segunda consulta a 'WHERE b.IsApproved = 1 o b.BarId is Null' es lo mismo. Ahora, ¿cuál haces? –

0

He visto algunos casos en los que el optimizador no era lo suficientemente inteligente incluso en versiones recientes de MSSQL, y la diferencia de rendimiento era monstruosa.

Pero esta es una excepción, la mayoría de las veces el optimizador de SQL Server resolverá el problema y obtendrá el plan correcto.

Mantienen la política de utilizar filtros en la cláusula WHERE y optimizan cuando sea necesario.

0

Acabo de ejecutar una prueba de una consulta contra cuatro tablas: una tabla principal con tres UNIONES INTERIORES y un total de cuatro parámetros, y comparé los planes de ejecución de ambos enfoques (usando los criterios de filtro en el ENCUADRE y luego también en la cláusula WHERE).

Los planes de ejecución son exactamente los mismos. Ejecuté esto en SQL Server 2008 R2.

Cuestiones relacionadas