Я столкнулся со странной ситуацией, когда добавление OPTION (RECOMPILE)
к моему запросу приводит к тому, что он выполняется за полсекунды, в то время как его пропуск приводит к тому, что запрос занимает больше пяти минут.
Это тот случай, когда запрос выполняется из Query Analyzer или из моей программы на C # через SqlCommand.ExecuteReader()
. Звонит (или не звонит) DBCC FREEPROCCACHE
или DBCC dropcleanbuffers
не имеет значения; Результаты запроса всегда возвращаются мгновенно OPTION (RECOMPILE)
и без него более пяти минут. Запрос всегда вызывается с одинаковыми параметрами [ради этого теста].
Я использую SQL Server 2008.
Я довольно хорошо пишу на SQL, но никогда раньше не использовал OPTION
команду в запросе и не был знаком с концепцией кэшей плана до тех пор, пока не просмотрел сообщения на этом форуме. Насколько я понимаю из постов, OPTION (RECOMPILE)
это дорогая операция. По-видимому, это создает новую стратегию поиска для запроса. Так почему же последующие запросы, которые опускаются, OPTION (RECOMPILE)
являются такими медленными? Разве последующие запросы не должны использовать стратегию поиска, которая была вычислена на предыдущем вызове, который включал подсказку перекомпиляции?
Весьма необычно иметь запрос, который требует подсказки перекомпиляции при каждом вызове?
Извините за вопрос начального уровня, но я не могу этого сделать.
ОБНОВЛЕНИЕ: меня попросили опубликовать запрос ...
select acctNo,min(date) earliestDate
from(
select acctNo,tradeDate as date
from datafeed_trans
where feedid=@feedID and feedDate=@feedDate
union
select acctNo,feedDate as date
from datafeed_money
where feedid=@feedID and feedDate=@feedDate
union
select acctNo,feedDate as date
from datafeed_jnl
where feedid=@feedID and feedDate=@feedDate
)t1
group by t1.acctNo
OPTION(RECOMPILE)
При запуске теста из Query Analyzer я добавляю следующие строки:
declare @feedID int
select @feedID=20
declare @feedDate datetime
select @feedDate='1/2/2009'
При вызове из моей программы на C # параметры передаются через SqlCommand.Parameters
свойство.
В целях этого обсуждения вы можете предположить, что параметры никогда не изменяются, поэтому мы можем исключить неоптимальный запах параметра в качестве причины.
источник
X = @X OR @X IS NULL
кX=@X
и выполняющее стремятся видеть здесь или нажав предикаты дальше вниз против зрения с оконными функциямиRECOMPILE
. В любом случае запишите планы выполнения и посмотрите на различия.Ответы:
Есть моменты, когда использование
OPTION(RECOMPILE)
имеет смысл. По моему опыту, единственно возможный вариант - когда вы используете динамический SQL. Прежде чем вы выясните, имеет ли это смысл в вашей ситуации, я бы порекомендовал пересмотреть статистику. Это можно сделать, выполнив следующее:А затем воссоздать ваш план выполнения. Это гарантирует, что при создании вашего плана выполнения он будет использовать самую последнюю информацию.
Добавление
OPTION(RECOMPILE)
перестраивает план выполнения каждый раз, когда выполняется ваш запрос. Я никогда не слышал, чтобы это описывалось как,creates a new lookup strategy
но, возможно, мы просто используем разные термины для одного и того же.Когда создается хранимая процедура (я подозреваю, что вы вызываете ad-hoc sql из .NET, но если вы используете параметризованный запрос, то это в конечном итоге является хранимым процедурным вызовом ) SQL Server пытается определить наиболее эффективный план выполнения для этого запроса. на основе данных в вашей базе данных и параметров, передаваемых в ( сниффинг параметров ), а затем кэширует этот план. Это означает, что если вы создаете запрос, в котором имеется 10 записей в вашей базе данных, а затем выполняете его, когда имеется 100 000 000 записей, кэшированный план выполнения может перестать быть наиболее эффективным.
Подводя итог, я не вижу причин, которые
OPTION(RECOMPILE)
могли бы принести пользу здесь. Я подозреваю, что вам просто нужно обновить статистику и план выполнения. Восстановление статистики может быть важной частью работы администратора баз данных в зависимости от вашей ситуации. Если после обновления вашей статистики у вас все еще есть проблемы, я бы предложил опубликовать оба плана выполнения.И чтобы ответить на ваш вопрос - да, я бы сказал, что для вас лучше всего перекомпилировать план выполнения каждый раз, когда вы выполняете запрос.
источник
OPTION (RECOMPILE)
решение может быть единственным решением.Часто, когда между запросами запускается радикальная разница, я обнаруживаю, что это часто одна из 5 проблем.
СТАТИСТИКА- Статистика устарела. База данных хранит статистику по диапазону и распределению типов значений в различных столбцах таблиц и индексов. Это помогает обработчику запросов разработать «план» атаки для того, как он будет выполнять запрос, например, тип метода, который он будет использовать для сопоставления ключей между таблицами, использующими хэш или просматривая весь набор. Вы можете вызвать обновление статистики для всей базы данных или только для определенных таблиц или индексов. Это замедляет запрос от одного прогона к другому, потому что, если статистика устарела, вполне вероятно, что план запроса не является оптимальным для вновь вставленных или измененных данных для того же запроса (более подробно будет объяснено ниже). Возможно, нецелесообразно немедленно обновлять статистику в производственной базе данных, так как будут некоторые накладные расходы, замедление и отставание в зависимости от объема данных для выборки. Вы также можете использовать полное сканирование или выборку для обновления статистики. Если вы посмотрите на план запроса, вы также сможете просмотреть статистику используемых индексов, например, с помощью командыDBCC SHOW_STATISTICS (имя таблицы, имя индекса) . Это покажет вам распределение и диапазоны ключей, которые план запроса использует для своего подхода.
ИЗМЕНЕНИЕ ПАРАМЕТРА - кэшированный план запроса не является оптимальным для конкретных параметров, которые вы передаете, даже если сам запрос не изменился. Например, если вы передадите параметр, который извлекает только 10 из 1 000 000 строк, то созданный план запроса может использовать Hash Join, однако если передаваемый параметр будет использовать 750 000 из 1 000 000 строк, созданный план может быть сканирование индекса или таблицы. В такой ситуации вы можете указать оператору SQL использовать опцию OPTION (RECOMPILE) или SP для использования с RECOMPILE. Сказать Механизму, что это «План одноразового использования», а не использовать кэшированный план, который, скорее всего, не применяется. Не существует правила о том, как принимать это решение, оно зависит от знания того, как пользователи будут использовать запрос.
ИНДЕКСЫ. Возможно, что запрос не изменился, но изменение в другом месте, например удаление очень полезного индекса, замедлило запрос.
ROWS CHANGED - Строки, которые вы запрашиваете, кардинально меняется от вызова к вызову. Обычно статистика автоматически обновляется в этих случаях. Однако, если вы создаете динамический SQL или вызываете SQL в узком цикле, есть вероятность, что вы используете устаревший план запросов, основанный на неправильном значительном числе строк или статистике. Опять же, в этом случае OPTION (RECOMPILE) полезен.
ЛОГИКА Это логика, ваш запрос больше не эффективен, он подходит для небольшого числа строк, но больше не масштабируется. Обычно это требует более глубокого анализа плана запросов. Например, вы больше не можете делать вещи навалом, но должны разбивать вещи на части и делать меньшие коммиты, или ваш кросс-продукт подходит для меньшего набора, но теперь занимает ЦП и память, поскольку масштабируется больше, это также может быть верно для используя DISTINCT, вы вызываете функцию для каждой строки, ваши совпадения ключей не используют индекс из-за преобразования типа CASTING или NULLS или функций ... Здесь слишком много возможностей.
В целом, когда вы пишете запрос, вы должны иметь представление о том, как определенные данные распределяются в вашей таблице. Например, столбец может иметь равномерно распределенное число различных значений или может быть искажен, 80% времени имеют определенный набор значений, независимо от того, будет ли распределение часто меняться со временем или будет довольно статичным. Это даст вам лучшее представление о том, как создать эффективный запрос. Но также при отладке производительности запросов есть основание для построения гипотезы о том, почему он медленный или неэффективный.
источник
Чтобы добавить в превосходный список (предоставленный @CodeCowboyOrg) ситуации, в которых OPTION (RECOMPILE) может быть очень полезным,
источник
Самые первые действия перед настройкой запросов - дефрагментировать / перестраивать индексы и статистику, иначе вы теряете время.
Вы должны проверить план выполнения, чтобы убедиться, что он стабилен (то же самое, когда вы меняете параметры), в противном случае вам, возможно, придется создать индекс покрытия (в данном случае для каждой таблицы) (зная систему, вы можете создать такой, который полезно и для других запросов).
в качестве примера: создать индекс idx01_datafeed_trans для datafeed_trans (feedid, feedDate) INCLUDE (acctNo, tradeDate)
если план стабилен или вы можете стабилизировать его, вы можете выполнить предложение с помощью sp_executesql («sql предложение»), чтобы сохранить и использовать фиксированный план выполнения.
если план нестабилен, вы должны использовать специальный оператор или EXEC («sql предложение»), чтобы каждый раз оценивать и создавать план выполнения. (или хранимая процедура "с перекомпиляцией").
Надеюсь, поможет.
источник
Отвечая на этот вопрос, но есть объяснение, которое, кажется, никто не рассматривал.
СТАТИСТИКА - Статистика недоступна или вводит в заблуждение
Если все следующее верно:
Тогда sql-сервер может ошибочно полагать, что столбцы некоррелированы, что приводит к более низким, чем ожидалось, оценкам количества элементов для применения обоих ограничений и выбору плохого плана выполнения. В этом случае исправлением будет создание объекта статистики, связывающего два столбца, что не является дорогой операцией.
источник