Заставить 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, - это создать простой план перебора, который просто сканирует всю таблицу, фильтруя строки по мере их поступления , без использования каких-либо показателей.

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

RBarryYoung
источник
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.

timvw
источник
Не могли бы вы уточнить, как может выглядеть конструкция if / else? : D
jcolebrand
Я собирался предложить использовать OPTION (WITH RECOMPILE), так как это будет генерировать идеальный план каждый раз - задержка компиляции добавит накладные расходы, но я подозреваю, что в этом случае в целом лучше.
SqlRyan