Запрос
SELECT SUM(Amount) AS SummaryTotal
FROM PDetail WITH(NOLOCK)
WHERE ClientID = @merchid
AND PostedDate BETWEEN @datebegin AND @dateend
Таблица содержит 103 129 000 строк.
Быстрый план ищет ClientId с остаточным предикатом на дату, но ему нужно выполнить 96 поисков для получения Amount
. <ParameterList>
Раздел в плане заключается в следующем.
<ParameterList>
<ColumnReference Column="@dateend"
ParameterRuntimeValue="'2013-02-01 23:59:00.000'" />
<ColumnReference Column="@datebegin"
ParameterRuntimeValue="'2013-01-01 00:00:00.000'" />
<ColumnReference Column="@merchid"
ParameterRuntimeValue="(78155)" />
</ParameterList>
Медленный план выполняет поиск по дате и имеет поиск для оценки остаточного предиката на ClientId и для получения суммы (оценка 1 против фактической 7 388 383). <ParameterList>
Раздел
<ParameterList>
<ColumnReference Column="@EndDate"
ParameterCompiledValue="'2013-02-01 23:59:00.000'"
ParameterRuntimeValue="'2013-02-01 23:59:00.000'" />
<ColumnReference Column="@BeginDate"
ParameterCompiledValue="'2013-01-01 00:00:00.000'"
ParameterRuntimeValue="'2013-01-01 00:00:00.000'" />
<ColumnReference Column="@ClientID"
ParameterCompiledValue="(78155)"
ParameterRuntimeValue="(78155)" />
</ParameterList>
Во втором случае ParameterCompiledValue
это не пустой. SQL Server успешно прослушал значения, используемые в запросе.
В книге «Практическое устранение неполадок SQL Server 2005» говорится об использовании локальных переменных.
Использование локальных переменных параметров поражения фырканья является довольно распространенным трюком, но OPTION (RECOMPILE)
и OPTION (OPTIMIZE FOR)
намеки ... , как правило , более элегантными и немного менее рискованные решения
Заметка
В SQL Server 2005 компиляция на уровне операторов позволяет откладывать компиляцию отдельного оператора в хранимой процедуре до первого выполнения запроса. К тому времени значение локальной переменной станет известно. Теоретически SQL Server может использовать это для анализа значений локальных переменных так же, как он анализирует параметры. Однако из-за того, что для предотвращения перехвата параметров в SQL Server 7.0 и SQL Server 2000+ обычно использовались локальные переменные, выслеживание локальных переменных не было включено в SQL Server 2005. Это может быть включено в будущем выпуске SQL Server, хотя это хорошо Причина использования одного из других вариантов, описанных в этой главе, если у вас есть выбор.
В результате быстрого тестирования, описанного выше, поведение, описанное выше, остается таким же в 2008 и 2012 годах, и переменные не отслеживаются для отложенной компиляции, а только при использовании явной OPTION RECOMPILE
подсказки.
DECLARE @N INT = 0
CREATE TABLE #T ( I INT );
/*Reference to #T means this statement is subject to deferred compile*/
SELECT *
FROM master..spt_values
WHERE number = @N
AND EXISTS(SELECT COUNT(*) FROM #T)
SELECT *
FROM master..spt_values
WHERE number = @N
OPTION (RECOMPILE)
DROP TABLE #T
Несмотря на отложенную компиляцию, переменная не прослушивается, и предполагаемое количество строк является неточным
Поэтому я предполагаю, что медленный план относится к параметризованной версии запроса.
Значение ParameterCompiledValue
равно ParameterRuntimeValue
для всех параметров, поэтому это не является типичным анализом параметров (где план был составлен для одного набора значений, а затем запущен для другого набора значений).
Проблема в том, что план, составленный для правильных значений параметров, не подходит.
Вероятно, вы столкнулись с проблемой возрастания дат, описанной здесь и здесь . Для таблицы с 100 миллионами строк вам нужно вставить (или иным образом изменить) 20 миллионов, прежде чем SQL Server автоматически обновит для вас статистику. Похоже, что в прошлый раз они обновляли нулевые строки, совпадающие с диапазоном дат в запросе, но теперь это делают 7 миллионов.
Вы можете запланировать более частые обновления статистики, рассмотреть флаги трассировки 2389 - 90
или использовать их, OPTIMIZE FOR UKNOWN
чтобы они просто возвращались к догадкам, а не могли использовать вводящую в заблуждение статистику по datetime
столбцу.
Это может быть необязательно в следующей версии SQL Server (после 2012 года). Связанный пункт Connect содержит интригующий ответ
Опубликовано Microsoft 28.08.2012 в 13:35
Мы сделали улучшение оценки мощности для следующего основного выпуска, которое по существу исправляет это. Следите за подробностями, как только появятся наши превью. Эрик
Это улучшение 2014 года рассматривается Бенджамином Неварезом в конце статьи:
Первый взгляд на новый оценщик мощности SQL Server .
Похоже, что новая оценка кардинальности откатится и в этом случае будет использовать среднюю плотность, а не оценку в 1 строку.
Некоторые дополнительные подробности об оценке кардинальности 2014 года и возрастающей ключевой проблеме здесь:
Новая функциональность в SQL Server 2014 - Часть 2. Новая оценка мощности
У меня была точно такая же проблема , когда хранимая процедура стала медленно, а
OPTIMIZE FOR UNKNOWN
иRECOMPILE
подсказки запросов разрешило медлительность и ускорили время выполнения. Однако следующие два метода не повлияли на медлительность хранимой процедуры: (i) очистка кэша (ii) с использованием WITH RECOMPILE. Так что, как вы и сказали, на самом деле это не было анализом параметров.Флаги трассировки 2389 и 2390 также не помогли. Просто обновление статистики (
EXEC sp_updatestats
) сделало это для меня.источник