Когда я запускаю следующий код, это занимает 22,5 минуты и читает 106 миллионов раз. Тем не менее, если я запускаю только внутреннюю инструкцию выбора, она занимает всего 15 секунд и читает 264 Кб. Как примечание, запрос на выборку не возвращает никаких записей.
Любая идея, почему это IF EXISTS
заставило бы это бежать намного дольше и делать так много чтений? Я также изменил оператор выбора, чтобы сделать, SELECT TOP 1 [dlc].[id]
и я убил его через 2 минуты.
В качестве временного исправления я изменил его на счетчик (*) и присвоил это значение переменной @cnt
. Тогда это делает IF 0 <> @cnt
заявление. Но я подумал, EXISTS
что будет лучше, потому что, если в операторе выбора будут возвращены записи, он прекратит сканирование / поиск, когда найдет хотя бы одну запись, тогда как count(*)
запрос завершит полный запрос. Что мне не хватает?
IF EXISTS
(SELECT [dlc].[ID]
FROM TableDLC [dlc]
JOIN TableD [d]
ON [d].[ID] = [dlc].[ID]
JOIN TableC [c]
ON [c].[ID] = [d].[ID2]
WHERE [c].[Name] <> [dlc].[Name])
BEGIN
<do something>
END
источник
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
.Ответы:
Как я объяснил в своем ответе на этот связанный вопрос:
Как (и почему) TOP влияет на план выполнения?
С помощью
EXISTS
вводит цель строки, где оптимизатор создает план выполнения, нацеленный на быстрое нахождение первой строки. При этом предполагается, что данные распределены равномерно. Например, если статистика показывает, что в 100 000 строк есть 100 ожидаемых совпадений, она будет предполагать, что для поиска первого совпадения потребуется прочитать только 1000 строк.Это приведет к увеличению времени выполнения, если это предположение окажется ошибочным. Например, если SQL Server выбирает метод доступа (например, неупорядоченное сканирование), который обнаруживает первое совпадающее значение очень поздно при поиске, это может привести к почти полному сканированию. С другой стороны, если в первых нескольких строках будет найдена совпадающая строка, производительность будет очень хорошей. Это фундаментальный риск для ряда целей - непоследовательная производительность.
Обычно можно переформулировать запрос так, чтобы цель строки не была назначена. Без цели строки запрос все еще может быть завершен при обнаружении первой подходящей строки (если она написана правильно), но стратегия плана выполнения, вероятно, будет другой (и, надеюсь, более эффективной). Очевидно, что count (*) потребует чтения всех строк, поэтому это не идеальная альтернатива.
Если вы работаете с SQL Server 2008 R2 или более поздней версии , вы также можете использовать документированный и поддерживаемый флаг трассировки 4138, чтобы получить план выполнения без цели строки. Этот флаг также может быть указан с помощью поддерживаемой подсказки
OPTION (QUERYTRACEON 4138)
, хотя имейте в виду , что для этого требуется разрешение системного администратора во время выполнения , если только оно не используется с руководством по планированию.к несчастью
Ничто из вышеперечисленного не является функциональным с
IF EXISTS
условным утверждением. Это относится только к обычному DML. Это будет работать с альтернативнойSELECT TOP (1)
формулировкой, которую вы пробовали. Это может быть лучше, чем использоватьCOUNT(*)
, которое должно подсчитывать все подходящие строки, как упоминалось ранее.Тем не менее, существует множество способов выразить это требование, которое позволит вам избежать или контролировать цель строки, в то же время досрочно завершив поиск. Последний пример:
источник
Поскольку EXISTS нужно только найти одну строку, он будет использовать цель строки, равную единице. Иногда это может привести к не совсем идеальному плану. Если вы ожидаете, что это будет так для вас, заполните переменную с результатом
COUNT(*)
а затем протестируйте эту переменную, чтобы увидеть, больше ли это 0.Итак ... С небольшой целью строки это позволит избежать блокирующих операций, таких как построение хеш-таблиц или сортировка потоков, которые могут быть полезны для объединений слиянием, потому что это будет показывать, что он обязательно найдет что-то довольно быстро, и поэтому вложенные циклы будут будет лучше, если он что-то найдет. За исключением того, что это может составить план, который намного хуже по всему набору. Если бы поиск одной строки был быстрым, вы бы хотели этот метод, чтобы избежать блоков ...
источник