Описанное вами поведение часто связано с неверно кэшированным планом запросов и / или устаревшей статистикой.
Обычно это происходит, когда в предложении WHERE имеется большое количество параметров, особенно длинный список тех, которые имеют форму:
(@parameter1 is NULL OR TableColumn1 = @parameter1)
Скажем, срок действия кэшированного запроса истекает, и процедура вызывается с непредставительным набором параметров. Затем план кэшируется для этого профиля данных. НО, если процесс чаще всего встречается с совершенно другим набором параметров, план может быть неуместным. Это часто называют «анализом параметров».
Существуют способы смягчения и устранения этой проблемы, но они могут включать компромиссы и зависеть от вашей версии SQL Server. Посмотрите на OPTIMIZE FOR
и OPTIMIZE FOR UNKNOWN
. Если (и это большое, если) процесс вызывается нечасто, но должен выполняться как можно быстрее, вы можете пометить его как OPTION(RECOMPILE)
, чтобы принудительно перекомпилировать каждый раз, когда он вызывается, НО не делать это для часто вызываемых процедур ИЛИ без расследования.
[ПРИМЕЧАНИЕ: знайте, какой Пакет обновления и накопительное обновление (CU) имеется в вашем SQL Server 2008, поскольку в некоторых версиях логика перекомпиляции и анализа параметров работает по-разному]
Запустите этот запрос (от Гленна Берри), чтобы определить состояние статистики:
-- When were Statistics last updated on all indexes?
SELECT o.name, i.name AS [Index Name],
STATS_DATE(i.[object_id], i.index_id) AS [Statistics Date],
s.auto_created, s.no_recompute, s.user_created, st.row_count
FROM sys.objects AS o WITH (NOLOCK)
INNER JOIN sys.indexes AS i WITH (NOLOCK)
ON o.[object_id] = i.[object_id]
INNER JOIN sys.stats AS s WITH (NOLOCK)
ON i.[object_id] = s.[object_id]
AND i.index_id = s.stats_id
INNER JOIN sys.dm_db_partition_stats AS st WITH (NOLOCK)
ON o.[object_id] = st.[object_id]
AND i.[index_id] = st.[index_id]
WHERE o.[type] = 'U'
ORDER BY STATS_DATE(i.[object_id], i.index_id) ASC OPTION (RECOMPILE);