Временные проблемы с производительностью функции SQL Server - PullRequest
0 голосов
/ 29 января 2011

В нашей базе данных есть функция, которая ищет две большие таблицы, чтобы узнать, существует ли значение.Это довольно большой запрос, но он оптимизирован для использования индексов и, как правило, выполняется довольно быстро.

Три раза за последние 2 недели эта функция решила не работать и работать очень медленно, что вызывает взаимоблокировку и плохую работупроизводительность вокруг.Это происходит даже в периоды, когда использование меньше, чем пиковое значение.

Восстановление функции с помощью «Изменение функции» в SQL Server, похоже, решает проблему.Как только мы это сделаем, использование сервера нормализуется, и все в порядке.

Это заставляет нас думать, что план запроса функций перестроен и учитывает правильные индексы, но мы понятия не имеемпочему SQL Server решил внезапно изменить план запроса на худший.

У кого-нибудь есть идеи, что может вызвать такое поведение, или как проверить его, или предотвратить?Мы работаем с SQL Server 2008 Enterprise.

1 Ответ

5 голосов
/ 29 января 2011

Описанное вами поведение часто связано с неверно кэшированным планом запросов и / или устаревшей статистикой.

Обычно это происходит, когда в предложении 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); 
...