Eu tenho duas mesas
@T1 TABLE
(
Id INT,
Date DATETIME
)
@T2 TABLE
(
Id INT,
Date DATETIME
)
Essas tabelas têm um índice não clusterizado em (Id, Data)
E eu junto essas mesas
SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON
t1.Id = t2.Id
WHERE
t1.Date <= GETDATE()
AND
t2.Date <= GETDATE()
Isso também pode ser escrito como
SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON
t1.Id = t2.Id
AND
t1.Date <= GETDATE()
AND
t2.Date <= GETDATE()
Minha pergunta é: qual dessas duas consultas oferece o melhor desempenho e por quê? Ou são iguais?
O desempenho será o mesmo. O otimizador reconhecerá isso e criará o mesmo plano.
Por outro lado, eu não diria que são iguais. A primeira forma da pergunta é muito mais legível e geralmente esperada.
Para um exemplo usando algumas tabelas que tenho em mãos, você pode ver que o plano de execução é exatamente o mesmo, não importa como eu escreva a consulta.
Você deve ser capaz de determinar os planos de consulta para suas próprias tabelas e conjuntos de dados para poder ver o que acontece em sua situação.
Dá esses planos de execução
Eles são semanticamente idênticos e o otimizador não deve ter problemas para reconhecer esse fato e gerar planos idênticos.
Costumo colocar condições referenciando ambas as tabelas no
ON
e condições referenciando apenas uma tabela noWHERE
.No
OUTER JOINS
entanto, para mover, as condições podem afetar a semântica.Em casos simples, será o mesmo. No entanto, tenho visto consultas muito complexas com várias junções com planos significativamente diferentes. Um recente em que eu estava trabalhando começou com uma tabela que tem cerca de 6 milhões de linhas unidas a cerca de 20 tabelas diferentes. Somente a primeira junção a esta tabela foi uma junção interna , todas as outras foram deixadas como junções externas. O filtro na cláusula where foi parametrizado mais ou menos assim:
Esse filtro foi usado posteriormente no plano em vez de anteriormente. Quando movi essas condições para a primeira junção interna, o plano mudou drasticamente, pois o filtro foi aplicado no início do plano para limitar o conjunto de resultados e minha CPU e o tempo decorrido caíram aproximadamente 310%. Então, como acontece com muitas questões do SQL Server, depende.
Em geral, onde você coloca os filtros faz diferença.
Embora Tom V diga que o Optimizer reconhecerá que as consultas são as mesmas e apresentará o mesmo plano, isso nem sempre é verdade. Depende de qual versão do SQL você está, quão complexa é sua consulta e quão importante para o lote geral o Otimizador determina que a consulta é.
O Otimizador pode decidir que esta parte do lote não vale a pena gastar tempo suficiente para permitir que ele apresente o melhor plano. Em geral, você obterá um melhor desempenho se colocar condições que reduzam a quantidade de dados que a consulta precisará para trabalhar na cláusula ON em vez da cláusula WHERE (se possível, pois fazer isso com uma junção externa resultará em um produto cartesiano . )
É um pouco mais fácil para o desenvolvedor SQL ocasional localizar filtros na cláusula WHERE, mas trabalhei em algumas tabelas grandes onde ter os filtros na cláusula ON economiza horas no tempo de execução.
Portanto, se a cláusula tiver o potencial de reduzir drasticamente o número de linhas que a consulta lerá, sempre a colocarei na cláusula ON para ajudar o Otimizador a escolher o melhor plano.
Em circunstâncias comuns, as condições do filtro podem ser especificadas nas cláusulas WHERE ou JOIN. Costumo colocar filtros em WHERE, a menos que a precedência OUTER JOIN possa ser afetada (veja abaixo) ou se o filtro for muito específico para essa tabela (por exemplo, TYPE=12 para especificar um subconjunto específico de linhas na tabela).
Por outro lado, as cláusulas ON e WHERE podem ser usadas para especificar as condições de junção (em oposição às condições de filtro). Contanto que você esteja usando apenas junções INNER, ainda não importa qual você usa em circunstâncias normais.
Se você estiver usando junções OUTER, no entanto, isso pode fazer uma grande diferença. Se, por exemplo, você especificar um OUTER JOIN entre duas tabelas (t1 e t2), mas depois, na cláusula WHERE, especificar um relacionamento eqijoin entre as tabelas (por exemplo, t1.col = t2.col), você acabou de converteu a junção OUTER em uma junção INNER! Isso ocorre porque WHERE pode ser usado para especificar um equijoin (ou talvez até OUTER join, dependendo da versão, usando a obsoleta sintaxe *=) sem usar uma cláusula ON, e quando WHERE indica um equijoin interno entre tabelas, ele substitui um OUTER JOIN (se presente).
A pergunta original era sobre filtros, onde o tipo de junção geralmente não deveria ser um problema, mas uma junção também pode atuar como um filtro e, nessas situações, o posicionamento da condição de junção certamente pode ser importante.
Com INNER JOINs, é uma questão de estilo.
No entanto, torna-se muito mais interessante com OUTER JOINs. Você deve explorar as diferenças entre consultas com OUTER JOINs e condições nas cláusulas ON e WHERE. O conjunto de resultados nem sempre é o mesmo. É, por exemplo,
o mesmo que