Монументальная разница во времени выполнения между запросами при использовании подсказки запроса RECOMPILE

16

У меня есть два почти идентичных запроса на одном экземпляре SQL Server 2005:

  1. Первый - это оригинальный SELECTзапрос, сгенерированный LINQ (я знаю, я знаю ... я не разработчик приложений, просто администратор БД :).
  2. Второй точно такой же, как первый, добавленный OPTION (RECOMPILE)в конце.

Больше ничего не изменилось.

Первый занимает 55 секунд при каждом запуске.
Второй занимает 2 секунды.

Оба набора результатов идентичны.

Почему этот намек привел к такому значительному увеличению производительности?

В разделе «Книги онлайн» RECOMPILEне содержится подробного объяснения:

Указывает ядру СУБД SQL Server отказаться от плана, сгенерированного для запроса после его выполнения, заставляя оптимизатор запросов перекомпилировать план запроса при следующем выполнении того же запроса. Без указания RECOMPILE компонент Database Engine кэширует планы запросов и использует их повторно. При компиляции планов запросов подсказка запроса RECOMPILE использует текущие значения любых локальных переменных в запросе и, если запрос находится внутри хранимой процедуры, текущие значения передаются любым параметрам.

RECOMPILE - полезная альтернатива созданию хранимой процедуры, которая использует предложение WITH RECOMPILE, когда необходимо перекомпилировать только подмножество запросов внутри хранимой процедуры, а не всю хранимую процедуру. Для получения дополнительной информации см. Перекомпиляция хранимых процедур. RECOMPILE также полезен при создании руководств плана. Для получения дополнительной информации см. Оптимизация запросов в развернутых приложениях с помощью руководств по планированию.

Поскольку в моем запросе много локальных переменных, я предполагаю, что SQL Server способен (серьезно) оптимизировать его, когда я использую OPTION (RECOMPILE)подсказку запроса.

Куда бы я ни посмотрел, люди говорят, что этого OPTION (RECOMPILE)следует избегать. Объяснение этому обычно заключается в том, что при использовании этой подсказки SQL Server не может повторно использовать этот план исключения и, следовательно, каждый раз приходится тратить время на его перекомпиляцию.
(Но) Учитывая гигантское преимущество в производительности, я склонен думать, что использование этого подсказки для запроса на этот раз было бы хорошо.

Должен ли я использовать это? Если нет, то есть ли способ заставить SQL Server использовать лучший план выполнения без этой подсказки и без изменения приложения?

ivanmp
источник

Ответы:

16

Как описано в статье Статистика, используемая оптимизатором запросов в Microsoft SQL Server 2005

Если вы используете локальную переменную в предикате запроса вместо параметра или литерала, оптимизатор прибегает к оценке пониженного качества или предположению селективности предиката. Используйте параметры или литералы в запросе вместо локальных переменных

Если оптимизатор не имеет полезной статистики для столбца, он будет предполагать, что =предикат будет соответствовать 10% строк, BETWEEN9%, а любой из них >, >=, < and <=будет совпадать с 30%. Если имеется доступная статистика столбцов, =предикат будет обрабатываться иначе, как показано ниже.

Даже когда в запросе используются локальные переменные, в случае предикатов равенства используется оценка, которая лучше, чем догадка. Селективность для условий вида " @local_variable = column_name" оценивается с использованием среднего значения частоты из гистограммы для column_name. Так, например, если столбец column_name содержит все уникальные значения, то 1/(number of unique values in column)будет использоваться оценка избирательности , которая является точной.

Так что это по сути то же самое, что и использование для OPTIMIZE FOR (UNKNOWN). Это может быть более точным, чем плоское 10%предположение, но оно не адаптировано к конкретным значениям, которые вы запрашиваете.

Чтобы заставить SQL Server оптимизировать запрос каждый раз, когда он выполняется, и использовать значения локальных переменных для оценки количества элементов и стоимости при оптимизации запроса, добавьте RECOMPILEподсказку запроса в запрос.

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

Мартин Смит
источник