Condição dentro de JOIN ou WHERE

Existe alguma diferença (desempenho, melhores práticas, etc …) entre colocar uma condição na cláusula JOIN vs. a cláusula WHERE?

Por exemplo…

-- 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' 

Qual você prefere (e talvez por quê)?

A álgebra relacional permite a intercambiabilidade dos predicados na cláusula WHERE e no INNER JOIN , portanto, mesmo consultas INNER JOIN com cláusulas WHERE podem ter os predicados rearranjados pelo otimizador para que eles possam já ser excluídos durante o processo JOIN .

Eu recomendo que você escreva as consultas da maneira mais legível possível.

Às vezes isso inclui tornar o INNER JOIN relativamente “incompleto” e colocar alguns dos critérios no WHERE simplesmente para tornar as listas de critérios de filtragem mais fáceis de manter.

Por exemplo, em vez 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 

Escreva:

 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 

Mas isso depende, claro.

Para junções internas, eu realmente não notei uma diferença (mas, como acontece com todo o ajuste de desempenho, você precisa verificar seu database sob as suas condições).

No entanto, onde você coloca a condição faz uma enorme diferença se você estiver usando junções esquerda ou direita. Por exemplo, considere estas duas 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' 

O primeiro fornecerá apenas os registros que tiverem um pedido com data posterior a 15 de maio de 2009, convertendo a junit esquerda em uma junit interna. O segundo fornecerá esses registros e todos os clientes sem pedidos. O conjunto de resultados é muito diferente dependendo de onde você coloca a condição. (Selecione * se, por exemplo, apenas para propósitos, você não deve usar obviamente em código de produção.) A exceção a isso é quando você deseja ver apenas os registros em uma tabela, mas não em outra. Então você usa a cláusula where para a condição e não a junit.

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

A maioria dos produtos RDBMS otimiza as duas consultas de maneira idêntica. Em “SQL Performance Tuning”, de Peter Gulutzan e Trudy Pelzer, eles testaram várias marcas de RDBMS e não encontraram diferença de desempenho.

Eu prefiro manter condições de junit separadas das condições de restrição de consulta.

Se você estiver usando o OUTER JOIN às vezes, é necessário colocar condições na cláusula de junit.

ONDE irá filtrar depois que o JOIN ocorreu.

Filtre no JOIN para impedir que as linhas sejam adicionadas durante o processo JOIN.

Eu prefiro o JOIN para unir tabelas / views completas e, em seguida, use o WHERE para introduzir o predicado do conjunto resultante.

Parece sintaticamente mais limpo.

Eu normalmente vejo aumentos de desempenho ao filtrar a associação. Especialmente se você puder juntar colunas indexadas para ambas as tabelas. Você deve ser capaz de reduzir leituras lógicas com a maioria das consultas fazendo isso também, o que é, em um ambiente de alto volume, um indicador de desempenho muito melhor do que o tempo de execução.

Sempre me sinto levemente divertido quando alguém mostra seu benchmarking de SQL e executam as duas versões de um sproc 50.000 vezes à meia-noite no servidor de desenvolvimento e comparam os tempos médios.

Colocar a condição na união parece “semanticamente errado” para mim, já que não é isso que JOINs é “para”. Mas isso é muito qualitativo.

Problema adicional: se você decidir mudar de uma junit interna para, digamos, uma junit direita, ter a condição dentro do JOIN pode levar a resultados inesperados.

As junções são mais rápidas na minha opinião quando você tem uma mesa maior. Realmente não é muita diferença, especialmente se você está lidando com uma mesa bem menor. Quando eu aprendi sobre junções, foi-me dito que as condições nas junções são exatamente como as condições cláusulas where e que eu poderia usá-los de forma intercambiável, se a cláusula where foi específica sobre qual tabela para fazer a condição em.

É melhor adicionar a condição na associação. O desempenho é mais importante que a legibilidade. Para grandes conjuntos de dados, é importante.