Non penso che abbia nulla a che fare con l'essere terribilmente lento; ha a che fare con l'essere potenzialmente inaccurati. Ad esempio, dati i seguenti dati - ordini che potrebbero essere effettuati da un singolo cliente o da un partner 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);
Diciamo che voglio trovare tutti i clienti che non hanno mai effettuato un ordine. Dati i dati, ce n'è solo uno: cliente n. 2. Ecco tre modi in cui potrei fare per scrivere una query per trovare quelle informazioni (ce ne sono altre):
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;
risultati:
NOT IN
------
-- <-- no results. Is that what you expected?
NOT EXISTS
----------
2
EXCEPT
------
2
Ora, ci sono anche alcuni problemi di prestazioni, e ne parlo in questo post sul blog . A seconda dei dati e degli indici, di NOT EXISTS
solito sovraperformerà NOT IN
e non so se potrebbe mai andare peggio. Dovresti anche notare che EXCEPT
puoi introdurre un'operazione di ordinamento distinta, quindi potresti finire con dati diversi (di nuovo, a seconda della fonte). E che il LEFT OUTER JOIN ... WHERE right.column IS NULL
modello popolare è sempre il peggiore.
Martin Smith ha anche molte buone informazioni di supporto nella sua risposta su SO .
IN
/NOT IN
sarà sempre implementato con anelli annidati. E non ho idea di cosastops SQL Server from creating a ‘plan’
dovrebbe significare.