Índice de desempenho em ON versus WHERE

26

Eu tenho duas mesas

@T1 TABLE
(
    Id INT,
    Date DATETIME
)

@T2 TABLE
(
    Id INT,
    Date DATETIME
)

Essas tabelas têm um índice não agrupado em (Id, Data)

E eu entro nessas tabelas

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 eles são iguais?

Erik Bergstedt
fonte
11
Você realmente tem uma tabela @ variada com um índice não agrupado que cobre todos os campos e nenhum índice agrupado? ou é apenas uma simplificação?
Remus Rusanu
11
É uma simplificação extrema
Erik Bergstedt

Respostas:

32

O desempenho será o mesmo. O otimizador reconhecerá isso e criará o mesmo plano.

Por outro lado, não diria que são iguais. A primeira forma da pergunta é muito mais legível e geralmente esperada.

Por exemplo, usando algumas tabelas que tenho em mãos, você pode ver que o plano de execução é exatamente o mesmo, independentemente de como escrevo a consulta.

Você deve poder determinar os planos de consulta para suas próprias tabelas e conjunto de dados, para poder ver o que acontece na sua situação.

SELECT * FROM salestable , custtable 
WHERE salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable 
JOIN  custtable 
ON salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable JOIN custtable 
ON salestable.custaccount = custtable.accountnum 
WHERE salestable.dataareaid = custtable.dataareaid

Dá esses planos de execução

insira a descrição da imagem aqui

Tom V - Equipe Monica
fonte
Concordo que a primeira forma é mais fácil de ler e, portanto, estou aliviada por serem iguais. Só usarei este formulário no futuro.
Erik Bergstedt
@ErikBergstedt Eu editei a minha resposta, você deve ser capaz de verificar isso para sua própria estrutura de conjunto de dados e mesa com bastante facilidade quando você olha para os planos de execução
Tom V - Team Monica
Sim eu fiz. Obrigado. Eu estava apenas procurando uma segunda opinião, pois não encontrei resposta.
Erik Bergstedt
Nota: Eles só são iguais se for um INNER JOIN. Se você jogar um OUTER JOIN, então eles decididamente não são os mesmos.
197 Kenneth Fisher
22

Eles são semanticamente idênticos e o otimizador não deve ter problemas para reconhecer esse fato e gerar planos idênticos.

Eu costumo colocar condições referenciando as duas tabelas no ONe condições referenciando apenas uma tabela no WHERE.

Para OUTER JOINSmover, as condições podem afetar a semântica, no entanto.

Martin Smith
fonte
7

Em casos simples, será o mesmo. No entanto, vi consultas muito complexas com várias associações terem planos significativamente diferentes. Uma recente na qual eu estava trabalhando começou com uma tabela que possui cerca de 6 milhões de linhas associadas a cerca de 20 tabelas diferentes. Somente a primeira junção a esta tabela foi uma junção interna ; todas as outras ficaram juntas externas. O filtro na cláusula where foi parametrizado da seguinte forma:

WHERE table1.begindate >= @startdate AND table1.enddate < @enddate 

Esse filtro foi usado posteriormente no plano, em vez de anteriormente. Quando mudei essas condições para a primeira junção interna, o plano mudou drasticamente quando 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%. Portanto, como em muitas perguntas do SQL Server, isso depende.

Jared Karney
fonte
2
Você poderia adicionar mais detalhes - talvez capturas de tela dos diagramas do plano de execução -, pois sua resposta parece contradizer todas as outras?
precisa saber é o seguinte
2
O plano mostrou um tempo limite do otimizador?
Martin Smith
Como a carga da CPU pode cair mais de 100%?
Michael Green
2

Em geral, onde você coloca os filtros faz a diferença.
Embora Tom V diga que o Otimizador reconhecerá que as consultas são iguais e criará o mesmo plano, isso nem sempre é verdade. Depende da versão do SQL, da complexidade da sua consulta e da importância para o lote geral que o Optimizer determina.

O Otimizador pode decidir que essa parte do lote não vale a pena gastar tempo suficiente para permitir que ele elabore o melhor plano. Em geral, você obterá melhor desempenho se colocar condições que reduzam a quantidade de dados na qual a consulta precisará 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 ocasional desenvolvedor SQL detectar filtros na cláusula WHERE, mas eu trabalhei em algumas tabelas grandes nas quais os filtros na cláusula ON eliminam horas do 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 Optimizer a escolher o melhor plano.

Tom Evers
fonte
1

Sob circunstâncias normais, as condições do filtro podem ser especificadas nas cláusulas WHERE ou JOIN. Eu 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 condições de junção (em oposição às condições de filtro). Enquanto você estiver usando apenas junções INNER, ainda não importa qual você usará em circunstâncias comuns.

Se você estiver usando junções OUTER, no entanto, isso pode fazer muita diferença. Se, por exemplo, você especificar um OUTER JOIN entre duas tabelas (t1 e t2), mas, na cláusula WHERE, especifique um relacionamento eqijoin entre as tabelas (por exemplo, t1.col = t2.col), você acabou de converteu a associação OUTER em uma associação INNER! Isso ocorre porque WHERE pode ser usado para especificar um equijoin (ou talvez uma junção OUTER, dependendo da versão, usando a sintaxe * = obsoleta) sem usar uma cláusula ON, e quando WHERE indica um equijoin interno entre as 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.

McB2K3
fonte
-1

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 na cláusula ON e na cláusula WHERE. O conjunto de resultados nem sempre é o mesmo. É, por exemplo,

OUTER JOIN dbo.x ON a.ID = x.ID ... WHERE x.SomeField IS NOT NULL

o mesmo que

INNER JOIN dbo.x ON a.ID = x.ID AND x.SomeField IS NOT NULL
Sean Redmond
fonte
8
Se o resultado for diferente (o que é claro), qual é o sentido de comparar o desempenho?
precisa saber é o seguinte