Existe uma prática recomendada entre usar o formato LEFT JOIN ou NOT EXISTS?
Qual é o benefício de usar um sobre o outro?
Se nenhum, qual deve ser o 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 do SQL Server.
sql-server
join
exists
Michael Richardson
fonte
fonte
WHERE A.idx NOT IN (...)
é não idênticas devido ao comportamento trivalente deNULL
(ou seja,NULL
não é igual aNULL
(nem desigual), portanto, se você tiver qualquerNULL
emtableB
que você vai obter resultados inesperados!)Respostas:
A maior diferença não está na junção vs não existe, é (como está escrito), o
SELECT *
.No primeiro exemplo, você obtém todas as colunas de ambos
A
eB
, enquanto no segundo exemplo, obtém apenas colunas deA
.No SQL Server, a segunda variante é um pouco mais rápida em um exemplo artificial muito simples:
Crie duas tabelas de amostra:
Insira 10.000 linhas em cada tabela:
Remova a cada quinta linha da segunda tabela:
Execute as duas
SELECT
variantes da instrução de teste :Planos de execução:
A segunda variante não precisa executar a operação de filtro, pois pode usar o operador de junção anti-semifacial esquerda.
fonte
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 um filtro (em vez de disponibilizá-las com valores NULL).Muitos anos atrás (SQL Server 6.0 ish),
LEFT JOIN
foi mais rápido, mas esse não é o caso há muito tempo. Hoje em dia,NOT EXISTS
é marginalmente mais rápido.O maior impacto no Access é que o
JOIN
método precisa concluir a associaçã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 olhar 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 é a "melhor prática", pois há mais fatores envolvidos.fonte
Uma exceção que eu notei ao
NOT EXISTS
ser superior (embora marginal)LEFT JOIN ... WHERE IS NULL
é ao usar Servidores Vinculados .Ao examinar os planos de execução, parece que o
NOT EXISTS
operador é executado de maneira aninhada. Pelo qual é executado em uma base por linha (o que suponho que faz sentido).Exemplo de plano de execução que demonstra esse comportamento:
fonte
INSERT INTO #t (a,b,c) SELECT a,b,c FROM LinkedServer.database.dbo.table WHERE x=y
depois executando aNOT EXISTS (...)
cópia temporária do banco de dados.Em geral, o mecanismo criará um plano de execução baseado essencialmente em:
Para 4):
O plano "não existe" incentiva um plano baseado em busca na tabela B. Essa é uma boa opção quando a tabela A é pequena e a tabela B é grande (e existe um índice em B).
O plano "antijoin" é uma boa opção quando a tabela A é muito grande ou a tabela B é muito pequena ou nenhum índice em B e retorna um grande conjunto de resultados.
No entanto, é apenas um "incentivo", como uma contribuição ponderada. Um forte (1), (2), (3) geralmente faz a escolha para (4) discussão.
(Ignorando o efeito do seu exemplo retornando colunas diferentes devido ao *, abordado pela resposta @MaxVernon.).
fonte