Condición dentro de JOIN o WHERE


194

¿Hay alguna diferencia (rendimiento, mejores prácticas, etc.) entre poner una condición en la cláusula JOIN frente a la cláusula WHERE?

Por ejemplo...

-- Condition in JOIN
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND CUS.FirstName = 'John'

-- Condition in WHERE
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE CUS.FirstName = 'John'

¿Cuál prefieres (y quizás por qué)?


44
¿Ejecutó las dos consultas? ¿Revisó los planes de ejecución generados por las dos consultas? ¿Qué observaste?
S.Lott

22
@ S.Lott, esta consulta es solo para fines de ejemplo. Me pregunto "en general" cuál es el método preferido, si lo hay.
Steve Dignan

1
@ Steve Dignan: debe comparar esto con datos de muestra y mirar los planes de consulta. La respuesta será muy, muy clara. Y, además, tendrá un código que podrá reutilizar cuando surjan situaciones más complejas.
S.Lott

1
Yo personalmente pondría la condición en la cláusula JOIN si la condición describe la relación. Las condiciones genéricas que simplemente filtran el conjunto de resultados irían a la parte WHERE entonces. Ej .FROM Orders JOIN OrderParties ON Orders.Id = OrderParties.Order AND OrderParties.Type = 'Recipient' WHERE Orders.Status = 'Canceled'
Glutexo

Respuestas:


154

El álgebra relacional permite la intercambiabilidad de los predicados en la WHEREcláusula y INNER JOIN, por lo tanto, incluso las INNER JOINconsultas con WHEREcláusulas pueden hacer que el optimizador reorganice los predicados para que puedan ser excluidos durante el JOINproceso.

Le recomiendo que escriba las consultas de la manera más legible posible.

A veces, esto incluye hacer lo INNER JOINrelativamente "incompleto" y poner algunos de los criterios WHEREsimplemente para hacer que las listas de criterios de filtrado sean más fáciles de mantener.

Por ejemplo, en lugar de:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
    AND c.State = 'NY'
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
    AND a.Status = 1

Escribir:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
    AND a.Status = 1

Pero depende, por supuesto.


77
No se trata solo de una consulta limpia o legibilidad, se trata del rendimiento. las condiciones de unión mejoran el rendimiento de una gran cantidad de datos con tablas correctamente indexadas.
Shahdat

1
Acabo de ejecutar informes de ventas mensuales uniendo 5-6 tablas en unos pocos millones de registros. El rendimiento mejora en un 30% - servidor sql 2012
Shahdat

2
@Shahdat si está obteniendo una diferencia de rendimiento tan significativa al mover las condiciones del filtro desde la cláusula where a la unión interna, debe publicar esos planes de ejecución.
Cade Roux

44
@Cade He investigado los planes de ejecución: ambos escenarios muestran el mismo costo. Ejecuto las consultas varias veces, parece que ambas toman el mismo tiempo. Anteriormente, estaba ejecutando las consultas en producción y obtuve una diferencia de rendimiento significativa porque la base de datos estaba siendo utilizada por usuarios en vivo. Perdón por esa confusión.
Shahdat

44
Esta respuesta es correcta para INNER JOINs pero no para izquierda / derecha.
sotn

123

Para las uniones internas, realmente no he notado una diferencia (pero como con todos los ajustes de rendimiento, debe verificar su base de datos bajo sus condiciones).

Sin embargo, donde coloca la condición hace una gran diferencia si está utilizando uniones izquierdas o derechas. Por ejemplo, considere estas dos consultas:

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderDate >'20090515'

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND ORD.OrderDate >'20090515'

El primero le dará solo aquellos registros que tengan un pedido con fecha posterior al 15 de mayo de 2009, lo que convierte la unión izquierda en una unión interna.

El segundo dará esos registros más cualquier cliente sin pedidos. El conjunto de resultados es muy diferente dependiendo de dónde coloque la condición. (Seleccionar * es solo para fines de ejemplo, por supuesto, no debe usar esto en el código de producción).

La excepción a esto es cuando desea ver solo los registros en una tabla pero no en la otra. Luego usa la cláusula where para la condición, no la unión.

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderID is null

Gracias por explicar con ejemplos
Rennish Joseph

1
"convirtiendo así la unión izquierda en una unión interna". ¿Cómo? ¿Puedes elaborar un poco?
user1451111

@ user1451111 Conozca lo que devuelve IZQUIERDA IZQUIERDA / DERECHA: filas de INNER JOIN más filas de tabla izquierda / derecha sin igual extendidas por NULL. FULL JOIN devuelve INNER JOIN filas UNION TODAS las filas de tabla izquierda y derecha no coincidentes extendidas por NULL. Siempre sepa qué INNER JOIN desea como parte de un OUTER JOIN. Un WHERE u ON que requiere que una columna posiblemente NULL-extendida no sea NULL después de que OUTER JOIN ON elimina cualquier fila extendida por NULL, es decir, deja solo filas de INNER JOIN, es decir, "convierte una OUTER JOIN en una INNER JOIN".
philipxy

1
@ user1451111 o, en términos más simples: A left join Bes cada fila de A unida a cada fila coincidente de B. Si B no tiene una fila que coincida, entonces las columnas A tienen un valor pero cada columna de B en esa fila se muestra como valores NULL. Si ha escrito, where B.somecolumn = ‘somevalue’entonces tiene un NULL (B.somecolumn) comparado con 'somevalue'. Cualquier cosa comparada con NULL es falsa, por lo que todas sus filas donde no hay una fila B coincidente para la fila A, se eliminan, y los resultados que obtiene son los mismos que daría una UNIÓN INTERNA, por lo tanto, la unión externa se ha convertido en una interna.
Caius Jard

Sí, he verificado que los resultados son los mismos para: SELECCIONAR fondos.id, prospects.id DESDE fundsla unión interna prospectos en (prospects.id = funds.lead_id y prospects.is_manual = 'no') y SELECCIONAR fondos.id, prospects.id DE fundsizquierda unirse a prospectos en (prospects.id = funds.lead_id) donde prospects.is_manual = 'no'
Rohit Dhiman

25

La mayoría de los productos RDBMS optimizarán ambas consultas de manera idéntica. En "SQL Performance Tuning" de Peter Gulutzan y Trudy Pelzer, probaron varias marcas de RDBMS y no encontraron diferencias de rendimiento.

Prefiero mantener las condiciones de unión separadas de las condiciones de restricción de consulta.

Si está utilizando a OUTER JOINveces es necesario poner condiciones en la cláusula de unión.


1
Estoy de acuerdo con usted en que sintácticamente es más limpio, y tengo que diferir su conocimiento de ese libro y su muy alta reputación, pero puedo pensar en 4 consultas en la última semana con planes de ejecución, tiempos de CPU y lecturas lógicas muy diferentes cuando Me mudé donde predicados a la unión.
marr75

2
Estabas preguntando sobre las mejores prácticas. Tan pronto como empiece a probar cómo funciona una implementación específica de RDBMS, otras personas han dado el consejo correcto: punto de referencia.
Bill Karwin

12

DONDE se filtrará después de que se haya producido la UNIÓN.

Filtre en JOIN para evitar que se agreguen filas durante el proceso de JOIN.


10
Semánticamente, se evitan durante el proceso INNER JOIN, pero el optimizador puede reorganizar INNER JOIN y WHERE predicados a voluntad, por lo que el optimizador puede excluirlos más tarde si lo desea.
Cade Roux

1
Cade Roux: Correcto. Muchas veces lo que escribe en SQL no es lo que le dará el optimizador cuando todo esté dicho y hecho. Me supongo entonces que esto sería justo en un mundo totalmente la teoría, mientras que su respuesta es por supuesto más correcto en el mundo de los optimizadores de consulta automática :)
TheTXI

Me gusta esta explicación de la condición en elON
Robert Rocha

3

Prefiero JOIN para unir tablas / vistas completas y luego usar WHERE para presentar el predicado del conjunto resultante.

Se siente sintácticamente más limpio.


2

Normalmente veo un aumento en el rendimiento al filtrar en la unión. Especialmente si puede unirse en columnas indexadas para ambas tablas. Debería poder reducir las lecturas lógicas con la mayoría de las consultas haciendo esto también, que es, en un entorno de alto volumen, un indicador de rendimiento mucho mejor que el tiempo de ejecución.

Siempre me divierte un poco cuando alguien muestra su evaluación comparativa de SQL y ha ejecutado ambas versiones de un sproc 50,000 veces a la medianoche en el servidor de desarrollo y compara los tiempos promedio.


0

Poner la condición en la combinación me parece "semánticamente incorrecto", ya que no es para eso que están "unidas". Pero eso es muy cualitativo.

Problema adicional: si decide cambiar de una unión interna a, por ejemplo, una unión correcta, tener la condición dentro de la UNIÓN podría generar resultados inesperados.


3
A veces, estos resultados son algo "esperados" y, a veces, incluso "intencionales" (por ejemplo, con uniones externas, donde la condición WHERE tiene una semántica diferente a la condición JOIN).
Marcel Toth

0

Las uniones son más rápidas en mi opinión cuando tienes una mesa más grande. Realmente no es una gran diferencia, especialmente si se trata de una mesa más pequeña. Cuando supe por primera vez sobre las combinaciones, me dijeron que las condiciones en las combinaciones son como las condiciones de la cláusula where y que podría usarlas indistintamente si la cláusula where fuera específica sobre qué tabla hacer la condición.


-4

Es mejor agregar la condición en la Unión. El rendimiento es más importante que la legibilidad. Para grandes conjuntos de datos, es importante.


1
¿Tiene algún tipo de prueba, investigue cómo la ubicación de los predicados mencionados afecta el rendimiento?
Zso
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.