Nie sądzę, żeby miało to coś wspólnego z byciem strasznie wolnym; ma to związek z potencjalnym niedokładnością. Na przykład, biorąc pod uwagę następujące dane - zamówienia, które mogą być składane przez klienta indywidualnego lub partnera 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);
Powiedzmy, że chcę znaleźć wszystkich klientów, którzy nigdy nie złożyli zamówienia. Biorąc pod uwagę dane, jest tylko jeden: klient nr 2. Oto trzy sposoby pisania zapytania w celu znalezienia tych informacji (są inne):
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;
Wyniki:
NOT IN
------
-- <-- no results. Is that what you expected?
NOT EXISTS
----------
2
EXCEPT
------
2
Teraz są też problemy z wydajnością i mówię o nich w tym poście na blogu . W zależności od danych i indeksów NOT EXISTS
zwykle osiągają lepsze wyniki NOT IN
, a ja nie wiem, czy może kiedykolwiek gorzej. Należy również pamiętać, że EXCEPT
można wprowadzić odrębną operację sortowania, co może skutkować uzyskaniem różnych danych (ponownie, w zależności od źródła). I że popularny LEFT OUTER JOIN ... WHERE right.column IS NULL
wzór jest zawsze najgorszy.
Martin Smith ma również wiele dobrych informacji pomocniczych w swojej odpowiedzi na temat SO .
IN
/NOT IN
zawsze będzie realizowany za pomocą zagnieżdżonych pętli. I nie mam pojęcia, costops SQL Server from creating a ‘plan’
to znaczy.