Заставить SQL Server выполнить условия запроса как написано?


14

Я использую SQL Server 2008 R2 и у меня есть этот псевдопросмотр (SP):

select ...
from ...
WHERE    @LinkMode IS NULL
     AND (myColumn IN (...very long-running query...))
     ...
     ...

Проблема в том, что выполнение запроса занимает очень много времени - даже если я выполняю SP с @LinkMode=2.

Как вы заметили, длительный запрос должен выполняться, только если @LinkMode имеет значение null, а здесь это не так. В моем случае @LinkMode = 2!

Однако, если я изменю это на:

 select ...
    from ...
    WHERE    1=2
         AND (myColumn IN (...very long time exeted query...))
     ...
     ...

СП действительно работать быстро.

Я слышал раньше, что иногда оптимизатор может оптимизировать порядок критериев.

Поэтому я спрашиваю:

  • Даже если оптимизатор выберет другой маршрут, что может быть быстрее проверки =null? Я имею в виду, я думаю , что проверка if a==nullявляется гораздо быстрее , чем при запуске другого длинного запроса ...

  • Как заставить SQL Server выполнить запрос, как я его написал (в том же порядке)?

Ответы:


22

Вы попадаете в ловушку " Catch-All Query ", которая очень хорошо объяснена Гейл Шоу здесь .

Чтобы подвести итог проблемы: SQL Server оптимизирует значительные накладные расходы на компиляцию запросов, кэшируя план запросов после компиляции, а затем проверяя кэш для соответствующего плана запросов перед последующей компиляцией. Происходящее здесь совпадение носит чисто текстовый характер, поэтому фактическое значение переменной не повлияет на это.

Это хорошо в 99% случаев, но в некоторых случаях это плохо . Один случай, когда это плохо, когда кто-то пытается создать предложение WHERE, как если бы оно было похоже на короткое замыкание оператора IF в C и т. Д. Это не работает хорошо, потому что компилятор SQL должен создать один план запроса, который будет работать независимо из того, что значения параметров на самом деле, и единственный способ, которым он может обрабатывать эти «умные» логические условия переключения в предложении WHERE, - это создать простой план перебора, который просто сканирует всю таблицу, фильтруя строки по мере их поступления , без использования каких-либо показателей.

Неудивительно, что это делает их равномерно медленными, независимо от значения параметра / переменной.


8

Не существует гарантированного способа заставить сервер SQL выполнять условия вашего предложения в определенной последовательности. Оптимизатор всегда оценивает их в том порядке, в каком считает нужным.

Что вы можете сделать, это что-то вроде этого:

IF @LinkMode IS NULL
BEGIN
    select ...
    from ...
    WHERE (myColumn IN (...very long time exeted query...))
         ...
         ...
END
ELSE
BEGIN
    select ...
    from ...
    WHERE ...
         ...
END

3

Если это вариант, используйте оператор IF для выполнения соответствующей формы запроса. Кроме того, в SQL вы указываете механизму БД, что делать, а не как это делать - вещи не выполняются от начала до конца. Может быть трудно предсказать, что именно это будет делать. Вы, вероятно, знаете это, хотя;)


2

Динамический SQL, вероятно, тоже будет работать, так как в этом случае оптимизатор запросов должен получать фактические значения во время выполнения (исправьте меня, если я ошибаюсь, я на самом деле не уверен, но, похоже, не помню, чтобы использовать его для подобных ситуаций) . Но я с другими в этом, потому что предложение IF / ELSE будет вам лучше, так как это самое простое и простое решение, которое будет делать именно то, что нужно.

Для дальнейшего использования, если вы еще не использовали его, здесь можно найти ужасно уродливый сайт с рабочим примером динамического SQL: http://sqlusa.com/bestpractices/dynamicsql/


1

Я бы порекомендовал конструкцию IF / ELSE. Если по какой-либо причине это не работает для вас, вы всегда можете использовать опцию WITH RECOMPILE.


Не могли бы вы уточнить, как может выглядеть конструкция if / else? : D
jcolebrand

Я собирался предложить использовать OPTION (WITH RECOMPILE), так как это будет генерировать идеальный план каждый раз - задержка компиляции добавит накладные расходы, но я подозреваю, что в этом случае в целом лучше.
SqlRyan
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.