NÃO deve ser evitado?

14

Entre alguns desenvolvedores do SQL Server, é uma crença amplamente difundida que NOT INé terrivelmente lenta e as consultas devem ser reescritas para que eles retornem o mesmo resultado, mas não usem as palavras-chave "más". ( exemplo ).

Há alguma verdade nisso?

Existe, por exemplo, algum bug conhecido no SQL Server (qual versão?) Que faz com que as consultas NOT INtenham um plano de execução pior do que uma consulta equivalente que use

  • um LEFT JOINcombinado com um NULLcheque ou
  • (SELECT COUNT(*) ...) = 0na WHEREcláusula?
Heinzi
fonte
7
Esse artigo é altamente impreciso. "In" não "precisa executar a mesma consulta repetidamente para cada linha do TableOne". O pôster parece acreditar que IN/ NOT INsempre será implementado com loops aninhados. E não tenho ideia do que stops SQL Server from creating a ‘plan’deve significar.
Martin Smith
5
@ Heinzi Esse artigo ao qual você vincula, deve morrer no fogo, é cheio de bobagens. Como: "Para substituir IN, usamos um INNER JOIN. Eles são efetivamente a mesma coisa." O problema é que eles não são a mesma coisa. Eu não confiaria em alguém que não conhece SQL básico, ou seja, a diferença entre uma junção e uma semi-junção, para analisar qualquer coisa sobre o comportamento do SQL-Server.
ypercubeᵀᴹ

Respostas:

14

Não acho que tenha algo a ver com ser terrivelmente lento; tem a ver com ser potencialmente impreciso. Por exemplo, dados os seguintes dados - pedidos que podem ser feitos por um cliente individual ou por um parceiro B2B:

DECLARE @Customers TABLE(CustomerID INT);

INSERT @Customers VALUES(1),(2);

DECLARE @Orders TABLE(OrderID INT, CustomerID INT, CompanyID INT);

INSERT @Orders VALUES(10,1,NULL),(11,NULL,5);

Digamos que eu queira encontrar todos os clientes que nunca fizeram um pedido. Dados os dados, há apenas um: cliente nº 2. Aqui estão três maneiras pelas quais eu poderia escrever uma consulta para encontrar essas informações (existem outras):

SELECT [NOT IN] = CustomerID FROM @Customers 
  WHERE CustomerID NOT IN (SELECT CustomerID FROM @Orders);

SELECT [NOT EXISTS] = CustomerID FROM @Customers AS c 
  WHERE NOT EXISTS (SELECT 1 FROM @Orders AS o
  WHERE o.CustomerID = c.CustomerID);

SELECT [EXCEPT] = CustomerID FROM @Customers
EXCEPT SELECT CustomerID FROM @Orders;

Resultados:

NOT IN
------
                 -- <-- no results. Is that what you expected?

NOT EXISTS
----------
2

EXCEPT
------
2

Agora, também existem alguns problemas de desempenho, e eu falo sobre eles nesta postagem do blog . Dependendo dos dados e índices, NOT EXISTSgeralmente terá um desempenho superior NOT IN, e não sei se poderia ter um desempenho pior. Você também deve observar que EXCEPTpode introduzir uma operação de classificação distinta, para que você possa acabar com dados diferentes (novamente, dependendo da fonte). E que o LEFT OUTER JOIN ... WHERE right.column IS NULLpadrão popular é sempre o pior artista.

Martin Smith também tem muitas informações de suporte boas em sua resposta ao SO .

Aaron Bertrand
fonte