No creo que tenga nada que ver con ser terriblemente lento; tiene que ver con ser potencialmente inexacto. Por ejemplo, dados los siguientes datos: pedidos que pueden ser realizados por un cliente individual o un socio 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 quiero encontrar a todos los clientes que nunca han realizado un pedido. Dados los datos, solo hay uno: cliente # 2. Aquí hay tres formas en que podría escribir una consulta para encontrar esa información (hay otras):
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
Ahora, también hay algunos problemas de rendimiento, y hablo de ellos en esta publicación de blog . Dependiendo de los datos e índices, NOT EXISTS
generalmente tendrá un rendimiento superior NOT IN
, y no sé si alguna vez podría funcionar peor. También debe tener en cuenta que EXCEPT
puede introducir una operación de clasificación distinta, por lo que puede terminar con datos diferentes (nuevamente, dependiendo de la fuente). Y que el LEFT OUTER JOIN ... WHERE right.column IS NULL
patrón popular es siempre el de peor desempeño.
Martin Smith también tiene mucha buena información de respaldo en su respuesta sobre SO .
IN
/NOT IN
siempre se implementará con bucles anidados. Y no tengo idea de lo questops SQL Server from creating a ‘plan’
se supone que significa.