Запит є
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 - Оцінка нової кардинальності