Condición dentro de JOIN o WHERE
¿Existe alguna diferencia (rendimiento, mejores prácticas, etc.) entre poner una condición en la cláusula JOIN y 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é)?
El álgebra relacional permite la intercambiabilidad de los predicados en la WHERE
cláusula y el INNER JOIN
, por lo que incluso INNER JOIN
las consultas con WHERE
cláusulas pueden tener los predicados reorganizados por el optimizador para que ya puedan ser excluidos durante el JOIN
proceso.
Te recomiendo que escribas las consultas de la forma más legible posible.
A veces, esto incluye hacer que las listas de INNER JOIN
criterios de filtrado sean relativamente "incompletas" y poner algunos de los criterios simplemente WHERE
para 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, claro.
Para las uniones internas realmente no he notado una diferencia (pero como ocurre con todos los ajustes de rendimiento, debe comparar con su base de datos según sus condiciones).
Sin embargo, el lugar donde se coloca la condición hace una gran diferencia si se utilizan combinaciones izquierda o derecha. 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 proporcionará sólo aquellos registros que tengan un pedido con fecha posterior al 15 de mayo de 2009, convirtiendo así la combinación izquierda en una combinación interna.
El segundo proporcionará esos registros más los clientes sin pedidos. El conjunto de resultados es muy diferente dependiendo de dónde coloques 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 de una tabla pero no de la otra. Luego usa la cláusula donde para la condición, no para 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
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 en el rendimiento.
Prefiero mantener las condiciones de unión separadas de las condiciones de restricción de consultas.
Si lo utiliza, OUTER JOIN
a veces es necesario poner condiciones en la cláusula de unión.