Я не думаю, что это имеет какое-то отношение к тому, чтобы быть ужасно медленным; это имеет отношение к тому, чтобы быть потенциально неточным. Например, с учетом следующих данных - заказов, которые могут быть размещены либо отдельным клиентом, либо партнером 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);
Допустим, я хочу найти всех клиентов, которые никогда не размещали заказ. Учитывая данные, есть только один: клиент № 2. Вот три способа написать запрос для поиска этой информации (есть и другие):
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;
Результаты:
NOT IN
------
-- <-- no results. Is that what you expected?
NOT EXISTS
----------
2
EXCEPT
------
2
Теперь есть некоторые проблемы с производительностью, и я расскажу о них в этом посте . В зависимости от данных и индексов, NOT EXISTS
как правило, выигрывают NOT IN
, и я не знаю, может ли он когда-либо работать хуже. Следует также отметить, что EXCEPT
может быть введена отдельная операция сортировки, поэтому вы можете получить разные данные (опять же, в зависимости от источника). И что популярный LEFT OUTER JOIN ... WHERE right.column IS NULL
шаблон всегда худший исполнитель.
У Мартина Смита также много полезной информации в ответе на SO .
IN
/NOT IN
всегда будет реализован с помощью вложенных циклов. И я понятия не имею, чтоstops SQL Server from creating a ‘plan’
должно означать.