Existe uma prática recomendada entre usar um formato LEFT JOIN ou NOT EXISTS?
Qual é a vantagem de usar um sobre o outro?
Se nenhum, qual deve ser preferido?
SELECT *
FROM tableA A
LEFT JOIN tableB B
ON A.idx = B.idx
WHERE B.idx IS NULL
SELECT *
FROM tableA A
WHERE NOT EXISTS
(SELECT idx FROM tableB B WHERE B.idx = A.idx)
Estou usando consultas no Access em um banco de dados SQL Server.
A maior diferença não está no join vs não existe, é (como está escrito), o
SELECT *
.No primeiro exemplo, você obtém todas as colunas de
A
eB
, enquanto no segundo exemplo, você obtém apenas colunas deA
.No SQL Server, a segunda variante é um pouco mais rápida em um exemplo muito simples:
Crie duas tabelas de amostra:
Insira 10.000 linhas em cada tabela:
Remova cada 5ª linha da segunda tabela:
Execute as duas
SELECT
variantes de instrução de teste:Planos de execução:
A segunda variante não precisa realizar a operação de filtro, pois pode usar o operador anti-semi-junção esquerdo.
Logicamente, eles são idênticos, mas
NOT EXISTS
estão mais próximos do AntiSemiJoin que você está solicitando e geralmente são os preferidos. Também destaca melhor que você não pode acessar as colunas em B, porque é usado apenas como filtro (em vez de tê-las disponíveis com valores NULL).Muitos anos atrás (SQL Server 6.0 ish),
LEFT JOIN
era mais rápido, mas isso não acontecia há muito tempo. Estes dias,NOT EXISTS
é marginalmente mais rápido.O maior impacto no Access é que o
JOIN
método precisa concluir a junção antes de filtrá-la, construindo o conjunto associado na memória. UsáNOT EXISTS
-lo verifica a linha, mas não aloca espaço para as colunas. Além disso, ele para de procurar quando encontra uma linha. O desempenho varia um pouco mais no Access, mas uma regra geral é queNOT EXISTS
tende a ser um pouco mais rápido. Eu estaria menos inclinado a dizer que é "melhor prática", pois há mais fatores envolvidos.Uma exceção que notei
NOT EXISTS
ser superior (ainda que marginalmente)LEFT JOIN ... WHERE IS NULL
é ao usar servidores vinculados .Ao examinar os planos de execução, parece que o
NOT EXISTS
operador é executado em um loop aninhado. Por meio do qual é executado por linha (o que suponho que faz sentido).Exemplo de plano de execução demonstrando esse comportamento:
Em geral, o motor irá criar um plano de execução baseado essencialmente em:
Para 4):
O plano "não existe" encoraja um plano baseado em busca na tabela B. Esta é uma boa escolha quando a tabela A é pequena e a tabela B é grande (e existe um índice em B).
O plano "antijoin" é uma boa escolha quando a tabela A é muito grande ou a tabela B é muito pequena ou nenhum índice em B e retorna um conjunto de resultados grande.
No entanto, é apenas um "incentivo", como uma entrada ponderada. Um forte (1),(2),(3) geralmente faz a escolha de (4) discutível.
( Ignorando o efeito do seu exemplo retornando colunas diferentes devido ao *. ).