SQL Server IN против производительности EXISTS - PullRequest
107 голосов
/ 14 января 2010

Мне любопытно, что из следующего ниже будет более эффективным?

Я всегда был немного осторожен с использованием IN, потому что я считаю, что SQL Server превращает набор результатов в большой оператор IF. Для большого набора результатов это может привести к снижению производительности. Для небольших наборов результатов я не уверен, что либо предпочтительнее. Для больших наборов результатов не будет ли EXISTS более эффективным?

WHERE EXISTS (SELECT * FROM Base WHERE bx.BoxID = Base.BoxID AND [Rank] = 2)

против

WHERE bx.BoxID IN (SELECT BoxID FROM Base WHERE [Rank = 2])

Ответы [ 9 ]

133 голосов
/ 14 января 2010

EXISTS будет быстрее, потому что, как только двигатель обнаружит удар, он перестанет выглядеть, поскольку условие подтвердилось.

При IN он соберет все результаты из подзапроса перед дальнейшей обработкой.

36 голосов
/ 09 октября 2014

Принятый ответ недальновиден, и в этом вопрос немного распущен:

1) Никто явно не упоминает, присутствует ли индекс покрытия в слева, справа или с обеих сторон.

2) Ни один из них не учитывает размер входного набора левой стороны и введите правую сторону.
(Вопрос только упоминает общий большой результат набор).

Я полагаю, что оптимизатор достаточно умен, чтобы конвертировать между "в" и "существует", когда существует значительная разница в стоимости из-за (1) и (2), в противном случае он может просто использоваться как подсказка (например, существует для поощрять использование поискового указателя на правой стороне).

Обе формы можно преобразовать для внутреннего объединения форм, изменить порядок объединения и запустить в виде цикла, хеша или слияния - на основе оценочного количества строк (слева и справа) и существования индекса слева, справа или обоих стороны.

35 голосов
/ 11 августа 2010

Я провел некоторое тестирование на SQL Server 2005 и 2008, и как EXISTS, так и IN вернулись с точно таким же реальным планом выполнения, как и другие заявили. Оптимизатор оптимален. :)

Что нужно знать, EXISTS, IN и JOIN могут иногда возвращать разные результаты, если вы не правильно сформулировали свой запрос: http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx

3 голосов
/ 14 января 2010

Планы выполнения обычно собираются быть идентичными в этих случаях, но пока вы не увидите, как оптимизатор учитывает все другие аспекты индексов и т. Д., Вы действительно никогда не узнаете.

3 голосов
/ 14 января 2010
2 голосов
/ 17 мая 2018

Таким образом, IN - это не то же самое, что EXISTS, и он не создаст тот же план выполнения.

Обычно EXISTS используется в коррелированном подзапросе, это означает, что вы СОЕДИНИТЕ внутренний запрос EXISTS со своим внешним запросом. Это добавит больше шагов для получения результата, так как вам нужно решить соединения внешнего запроса, и соединения внутреннего запроса затем сопоставят их предложения where, чтобы объединить оба.

Обычно IN используется без корреляции внутреннего запроса с внешним запросом, и это можно решить только за один шаг (в лучшем случае).

Учтите это:

  1. Если вы используете IN и результатом внутреннего запроса являются миллионы строк различных значений, он, вероятно, будет выполнять МЕДЛЕННО, чем EXISTS, учитывая, что запрос EXISTS является производительным (имеет правильные индексы для соединения с внешним запросом).

  2. Если вы используете EXISTS и соединение с внешним запросом является сложным (выполнение занимает больше времени, нет подходящих индексов), это приведет к замедлению запроса на количество строк во внешней таблице, иногда предполагаемое время для Завершить можно в днях. Если число строк является приемлемым для данного аппаратного обеспечения или количество элементов данных правильное (например, меньшее количество значений DISTINCT в большом наборе данных) IN может работать быстрее, чем EXISTS.

  3. Все вышеперечисленное будет отмечено, когда у вас будет достаточное количество строк в каждой таблице (под честным я подразумеваю нечто, превышающее пороговые значения обработки вашего ЦП и / или оперативной памяти для кэширования).

Итак, ОТВЕТ - ЗАВИСИМО. Вы можете написать сложный запрос внутри IN или EXISTS, но, как правило, вы должны попытаться использовать IN с ограниченным набором различных значений и EXISTS, когда у вас много строк с большим количеством различных значений.

Хитрость заключается в ограничении количества сканируемых строк.

С уважением,

MarianoC

1 голос
/ 04 декабря 2018

Здесь есть много вводящих в заблуждение ответов, в том числе и крайне одобренных (хотя я не верю, что их действия означали вред). Краткий ответ: это одно и то же.

Существует много ключевых слов в (T-) языке SQL, но, в конце концов, единственное, что действительно происходит на аппаратном уровне, - это операции, как видно из плана запроса на выполнение.

Реляционная (математическая теория) операция, которую мы выполняем при вызове [NOT] IN и [NOT] EXISTS, является полусоединением (против объединения при использовании NOT). Не случайно соответствующие операции sql-сервера имеют с таким же именем . Нет операции, которая упоминает IN или EXISTS где-либо - только (анти) полусоединения. Таким образом, не существует способа, которым логически эквивалентный выбор IN vs EXISTS мог бы повлиять на производительность, потому что существует один и единственный способ, (анти) операция соединения с полусоединением, чтобы получить свои результаты .

Пример:

Запрос 1 ( план )

select * from dt where dt.customer in (select c.code from customer c where c.active=0)

Запрос 2 ( план )

select * from dt where exists (select 1 from customer c where c.code=dt.customer and c.active=0)
1 голос
/ 05 апреля 2014

Чтобы оптимизировать EXISTS, будьте очень буквальными; что-то просто должно быть там, но на самом деле вам не нужны никакие данные, возвращаемые из коррелированного подзапроса. Вы просто оцениваете логическое условие.

Итак:

WHERE EXISTS (SELECT TOP 1 1 FROM Base WHERE bx.BoxID = Base.BoxID AND [Rank] = 2)

Поскольку коррелированный подзапрос имеет значение RBAR, первое попадание результата делает условие истинным и больше не обрабатывается.

0 голосов
/ 14 января 2010

С вершины моей головы и не гарантируется, что будет правильным: я считаю, что второе будет быстрее в этом случае.

  1. В первом случае коррелированный подзапрос, вероятно, вызовет выполнение подзапроса для каждой строки.
  2. Во втором примере подзапрос должен выполняться только один раз, поскольку он не коррелирован.
  3. Во втором примере IN замкнется, как только найдет совпадение.
...