Дополнительно
NOT IN vs NOT EXISTS
Какой из этих запросов быстрее?
NOT EXISTS:
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE NOT EXISTS (
SELECT 1
FROM Northwind..[Order Details] od
WHERE p.ProductId = od.ProductId)
или NOT IN:
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE p.ProductID NOT IN (
SELECT ProductID
FROM Northwind..[Order Details])
План выполнения запроса говорит, что они оба делают одно и то же. Если это так, то какая форма является рекомендуемой?
Это основано на базе данных NorthWind.
[Редактировать].
Только что нашел эту полезную статью: http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx
Думаю, я буду придерживаться NOT EXISTS.
502
10
Я всегда по умолчанию
не существует
.Выполнение планов могут быть одинаковыми, но если какой-либо столбец изменить в будущем, чтобы разрешить значение null в
не в
версии придется делать больше работы (даже если нетнуль фактически присутствующих в данных) и семантика
не весли
нуль это может представить, вряд ли будут те, что вы хотите в любом случае.Когда ни продуктов.Кодтовара
или
[детали заказа].Кодтовара "разрешить" нуль еще не будут относиться одинаково к следующего запроса.Точного плана могут различаться, но для моего примера данных, я получаю следующее.
Достаточно распространенное заблуждение, кажется, что коррелированные подзапросы всегда на "плохо" по сравнению с соединениями. Они, конечно, могут быть, когда они заставляют вложенного плана петель (подзапрос вычисляется построчно), но этот план включает в себя анти-полусоединение логический оператор. Анти полу соединений не ограничивается вложенными циклами, но может использовать хэш или слияния (как в данном примере) тоже присоединяется.
Если
[Детали Заказа].Кодтовара
нулевой
-может тогда запрос будетПричина этого заключается в том, что правильная семантика, если
[детали заказа]
содержитнуль
, `Кодтовара является не возвращают никаких результатов. Ознакомиться с дополнительной анти-полусоединение и число строк катушку, чтобы убедиться в этом, добавленная в план.Если
Продукты.Кодтовара также изменился и стал равен
null`-может тогда запрос будетПричина этому одна-это потому, что продукты "нуль"
.Кодтовара
не должен быть возвращен в результатах Кроме если не в подзапрос были вернуть никаких результатов вообще (т. е.[детали заказа]
таблица пуста). В этом случае следует. В план для моей выборки данных путем добавления еще одного анти-полусоединение, как показано ниже.Эффект это показано в блоге уже связаны Бакли. В примере есть числа логических чтений увеличится С 400 до 500 000.
Кроме того, тот факт, что один "нуль" может уменьшить количество строк до нуля делает оценки мощности очень сложно. Если SQL Server предполагает, что это произойдет, но в действительности нет
нуль
строк, в данные остальные выполнения плана может быть катастрофически хуже, если это только часть большого запроса, с неуместным вложенных циклов вызывает повторное выполнение дорогую поддерева, например.Это не единственно возможный план выполнения
не в
нануль
-в состоянии однако колонке. Эта статья показывает еще один для запроса к базе данных adventureworks2008`.Для
не
нане нуль
столбца илине существует
против либо значение null или номера столбца значение null дает следующий план.Когда колонна изменится на
нуль
-теперьне в
плане выглядитЭто добавляет дополнительное внутреннее соединение оператора плану. Этот аппарат объяснены здесь. Это все есть для преобразования предыдущим один коррелируется поиск по индексу продаж.Таблицы salesorderdetail.Кодтовара = на два направлен в наружную строку. Еще одно на
где продажи.Таблицы salesorderdetail.Кодтовара является null
.Как это под анти-полусоединение, если один возвращает ни одной строки второй искать не будет происходить. Однако если
продаж.Таблицы salesorderdetail
не содержитнуль
, `Кодтовара, это позволит удвоить количество искать необходимые операции.Также следует помнить, что не в это не равносильно тому, что не существует, когда дело доходит до нулевой.
Этот пост очень хорошо все объясняет
http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/
Если планировщик исполнения говорит, что они одинаковые, значит, они одинаковые. Используйте тот из них, который сделает ваше намерение более очевидным - в данном случае второй.
На самом деле, я считаю, что это было бы быстрее всего:
У меня есть таблица, которая имеет около 120 000 записей и нужно выбрать только те, которые не существуют (в сочетании с столбца varchar) в четырех других таблиц с числом строк, приблизительно 1500, 4000, 40000, 200. Все задействованные таблицы уникальный индекс на соответствующий столбец типа varchar`.
Не в
заняло около 10 минут,не существует
заняло 4 сек.У меня есть рекурсивный запрос, которая, возможно, имела некоторые расстроенные раздел, который, возможно, способствовал 10 минут, но другого варианта брать 4 секунд объясняет, по крайней мере для меня, что
не существует
гораздо лучше или, по крайней мере, чтов
исуществует
это не одно и то же и всегда стоит проверить, прежде чем идти вперед с кодом.В вашем конкретном примере они одинаковы, потому что оптимизатор понял, что вы пытаетесь сделать, это же в обоих примерах. Но вполне возможно, что в нетривиальных примеров оптимизатор не может сделать это, и в этом случае есть основания предпочитать, чтобы другие по случаю.
Не должно быть предпочтительнее, если вы тестируете несколько строк в ваш внешний выбор. Подзапрос внутри не в заявлении могут быть оценены в начале исполнения, и временные таблицы могут быть проверены на каждое значение во внешнем выбора, а не повторного выполнения подзапроса выборки каждый раз, как потребуется с
не существует` заявление.Если подзапрос должна быть соотнесены с внешней Select, после
не существует
может быть предпочтительнее, т. к. оптимизатор может обнаружить упрощение, что предотвращает создание временных таблиц для выполнения той же функции.Я использовал
и обнаружил, что она дает неверные результаты (неправильных я имею в виду не результаты). Как был нулем в table2.На col1.
При изменении запроса
дал мне правильные результаты.
С тех пор я начал использовать не существует каждый где.
Они очень похожи, но не одинаковы.
С точки зрения эффективности, я'вэ нашел левое соединение нуль заявление более эффективным (при обилии строк для выбранного)
Если оптимизатор говорит, что они одинаковые, то учитывать человеческий фактор. Я предпочитаю видеть не существует :)
Это зависит от...
не будет относительно медленным, так как не так уж и много, чтобы ограничить размер того, что запрос проверяет, есть ли в нем ключ. EXISTS был бы предпочтительнее в этом случае.
Но, в зависимости от оптимизатора СУБД, это может быть и не так.
В качестве примера того, когда EXISTS лучше