Qual dessas consultas é a mais rápida?
NÃO EXISTE:
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE NOT EXISTS (
SELECT 1
FROM Northwind..[Order Details] od
WHERE p.ProductId = od.ProductId)
Ou NÃO EM:
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE p.ProductID NOT IN (
SELECT ProductID
FROM Northwind..[Order Details])
O plano de execução da consulta diz que ambos fazem a mesma coisa. Se for esse o caso, qual é o formulário recomendado?
Isso é baseado no banco de dados NorthWind.
[Editar]
Acabei de encontrar este artigo útil: http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx
Eu acho que vou ficar com NÃO EXISTE.
sql
sql-server
notin
ilitirit
fonte
fonte
NOT IN
consulta:SELECT "A".* FROM "A" WHERE "A"."id" NOT IN (SELECT "B"."Aid" FROM "B" WHERE "B"."Uid" = 2)
é quase 30 vezes mais rápida que estaNOT EXISTS
:SELECT "A".* FROM "A" WHERE (NOT (EXISTS (SELECT 1 FROM "B" WHERE "B"."user_id" = 2 AND "B"."Aid" = "A"."id")))
Respostas:
Eu sempre padrão para
NOT EXISTS
.Os planos de execução podem ser os mesmos no momento, mas se alguma coluna for alterada no futuro para permitir
NULL
s, aNOT IN
versão precisará fazer mais trabalho (mesmo se nenhumNULL
s estiver realmente presente nos dados) e a semântica deNOT IN
seNULL
s estiver presente provavelmente não será o que você deseja.Quando nenhum
Products.ProductID
ou[Order Details].ProductID
permitirNULL
sNOT IN
serão tratados de forma idêntica à seguinte consulta.O plano exato pode variar, mas para os meus dados de exemplo, recebo o seguinte.
Um equívoco razoavelmente comum parece ser que as subconsultas correlacionadas são sempre "ruins" em comparação com as junções. Eles certamente podem ser quando forçam um plano de loops aninhados (subconsulta avaliada linha por linha), mas esse plano inclui um operador lógico anti-junção. As junções anti-semi não estão restritas a loops aninhados, mas também podem usar junções de hash ou mesclagem (como neste exemplo).
E se
[Order Details].ProductID
estiverNULL
ativável, a consulta se tornaráA razão para isso é que a semântica correta, se
[Order Details]
contém algumaNULL
ProductId
s, não retornará resultados. Consulte o spool anti-junção extra e contagem de linhas para verificar se foi adicionado ao plano.Se
Products.ProductID
também for alterado para se tornarNULL
possível, a consulta se tornaráA razão para isso é
NULL
Products.ProductId
que a não deve ser retornada nos resultados, exceto se aNOT IN
subconsulta não retornar nenhum resultado (isto é, o[Order Details]
tabela está vazia). Nesse caso, deveria. No plano para meus dados de amostra, isso é implementado adicionando outra anti-junção como abaixo.O efeito disso é mostrado em postagem do blog já vinculada por Buckley . No exemplo, o número de leituras lógicas aumenta de cerca de 400 para 500.000.
Além disso, o fato de um único
NULL
poder reduzir a contagem de linhas para zero dificulta muito a estimativa da cardinalidade. Se o SQL Server assumir que isso acontecerá, mas, de fato, não houveNULL
linhas nos dados, o restante do plano de execução poderá ser catastroficamente pior, se isso for apenas parte de uma consulta maior, com loops aninhados inadequados, causando a execução repetida de um sub caro árvore por exemplo .Entretanto, este não é o único plano de execução possível para uma coluna
NOT IN
onNULL
-able.Este artigo mostra outro para uma consulta noAdventureWorks2008
banco de dados.Para a
NOT IN
sobre umaNOT NULL
coluna ou oNOT EXISTS
contra anulável ou não anulável, fornece o plano a seguir.Quando a coluna muda para
NULL
-able, oNOT IN
plano agora pareceEle adiciona um operador de junção interna extra ao plano. Este aparelho é explicado aqui . Está tudo lá para converter a busca de índice correlativo único anterior em
Sales.SalesOrderDetail.ProductID = <correlated_product_id>
duas buscas por linha externa. O outro está ativadoWHERE Sales.SalesOrderDetail.ProductID IS NULL
.Como isso está sob uma junção anti-semi, se essa retornar linhas, a segunda busca não ocorrerá. No entanto, se
Sales.SalesOrderDetail
não contiver nenhumNULL
ProductID
s, dobrará o número de operações de busca necessárias.fonte
NOT EXISTS
funciona da maneira que eu esperoNOT IN
que funcione (o que não funciona).Lembre-se também de que NOT IN não é equivalente a NOT EXISTS quando se trata de nulo.
Este post explica muito bem
http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/
fonte
Se o planejador de execução diz que eles são iguais, eles são iguais. Use o que quer que torne sua intenção mais óbvia - neste caso, o segundo.
fonte
Na verdade, acredito que isso seria o mais rápido:
fonte
Eu tenho uma tabela que tem cerca de 120.000 registros e preciso selecionar apenas aqueles que não existem (correspondidos a uma coluna varchar) em outras quatro tabelas com número de linhas aproximadamente 1500, 4000, 40000, 200. Todas as tabelas envolvidas têm índice exclusivo na
Varchar
coluna em questão .NOT IN
levou cerca de 10 minutos,NOT EXISTS
levou 4 segundos.Eu tenho uma consulta recursiva que pode ter alguma seção sem sintonia que pode ter contribuído para os 10 minutos, mas a outra opção leva 4 segundos, pelo menos para mim que
NOT EXISTS
é muito melhor ou pelo menos issoIN
eEXISTS
não é exatamente o mesmo e sempre vale a pena. verifique antes de prosseguir com o código.fonte
No seu exemplo específico, eles são iguais, porque o otimizador descobriu o que você está tentando fazer é o mesmo nos dois exemplos. Mas é possível que em exemplos não triviais o otimizador possa não fazer isso e, nesse caso, há razões para preferir um ao outro ocasionalmente.
NOT IN
deve ser preferido se você estiver testando várias linhas em sua seleção externa. A subconsulta dentro daNOT IN
instrução pode ser avaliada no início da execução e a tabela temporária pode ser verificada em relação a cada valor na seleção externa, em vez de executar novamente a subseleção sempre que necessário com o parâmetroNOT EXISTS
instrução.Se a subconsulta precisar ser correlacionada com a seleção externa,
NOT EXISTS
poderá ser preferível, pois o otimizador poderá descobrir uma simplificação que impede a criação de tabelas temporárias para executar a mesma função.fonte
Eu estava usando
e descobriu que estava dando resultados errados (por errado, não quero dizer resultados). Como havia um NULL em TABLE2.Col1.
Ao alterar a consulta para
me deu os resultados corretos.
Desde então, comecei a usar NOT EXISTS em todos os lugares.
fonte
Eles são muito parecidos, mas não são realmente iguais.
Em termos de eficiência, descobri que a instrução de associação à esquerda é nula mais eficiente (quando é necessário selecionar uma abundância de linhas)
fonte
Se o otimizador disser que são os mesmos, considere o fator humano. Eu prefiro ver NÃO EXISTE :)
fonte
Modelo de tabela de banco de dados
Vamos supor que temos as duas tabelas a seguir em nosso banco de dados, que formam um relacionamento de tabela um para muitos.
A
student
tabela é o pai e astudent_grade
tabela filha, pois possui uma coluna Chave estrangeira student_id que faz referência à coluna Chave primária id na tabela do aluno.O
student table
contém os dois registros a seguir:E, a
student_grade
tabela armazena as notas que os alunos receberam:SQL EXISTS
Digamos que queremos que todos os alunos que tenham recebido nota 10 na aula de matemática.
Se estivermos interessados apenas no identificador de aluno, podemos executar uma consulta como esta:
Mas, o aplicativo está interessado em exibir o nome completo de a
student
, não apenas o identificador, por isso precisamos de informações dastudent
tabela também.Para filtrar os
student
registros que possuem nota 10 em matemática, podemos usar o operador EXISTS SQL, assim:Ao executar a consulta acima, podemos ver que apenas a linha Alice está selecionada:
A consulta externa seleciona as
student
colunas da linha que estamos interessados em retornar ao cliente. No entanto, a cláusula WHERE está usando o operador EXISTS com uma subconsulta interna associada.O operador EXISTS retornará true se a subconsulta retornar pelo menos um registro e false se nenhuma linha for selecionada. O mecanismo do banco de dados não precisa executar a subconsulta inteiramente. Se um único registro for correspondido, o operador EXISTS retornará true e a outra linha de consulta associada será selecionada.
A subconsulta interna é correlacionada porque a coluna student_id da
student_grade
tabela é comparada com a coluna id da tabela externa do aluno.SQL NÃO EXISTE
Vamos considerar que queremos selecionar todos os alunos que não têm nota inferior a 9. Para isso, podemos usar NOT EXISTS, o que nega a lógica do operador EXISTS.
Portanto, o operador NOT EXISTS retornará true se a subconsulta subjacente não retornar nenhum registro. No entanto, se um único registro for correspondido pela subconsulta interna, o operador NOT EXISTS retornará false e a execução da subconsulta poderá ser interrompida.
Para corresponder a todos os registros de alunos que não tenham associado student_grade a um valor menor que 9, podemos executar a seguinte consulta SQL:
Ao executar a consulta acima, podemos ver que apenas o registro de Alice é correspondido:
Portanto, a vantagem de usar os operadores SQL EXISTS e NOT EXISTS é que a execução da subconsulta interna pode ser interrompida enquanto for encontrado um registro correspondente.
fonte
Depende..
não seria relativamente lento, não há muito para limitar o tamanho do que a consulta verifica para ver se a chave está inserida. EXISTS seria preferível nesse caso.
Mas, dependendo do otimizador do DBMS, isso não poderia ser diferente.
Como um exemplo de quando EXISTS é melhor
fonte
IN
eEXISTS
obtenha o mesmo plano no SQL Server . A questão é sobreNOT IN
vs deNOT EXISTS
qualquer maneira.