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 EXISTS
geralmente terá um desempenho superior NOT IN
, e não sei se poderia ter um desempenho pior. Você também deve observar que EXCEPT
pode 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 NULL
padrão popular é sempre o pior artista.
Martin Smith também tem muitas informações de suporte boas em sua resposta ao SO .
IN
/NOT IN
sempre será implementado com loops aninhados. E não tenho ideia do questops SQL Server from creating a ‘plan’
deve significar.