Zachowanie, które opisujesz, jest często spowodowane niepoprawnie zbuforowanym planem zapytań i/lub nieaktualnymi statystykami.
Zwykle występuje, gdy masz dużą liczbę parametrów w klauzuli WHERE, szczególnie długą listę tych, które mają postać:
(@parameter1 is NULL OR TableColumn1 = @parameter1)
Powiedzmy, że buforowany plan zapytania wygasa, a proc jest wywoływana z niereprezentatywnym zestawem parametrów. Plan jest następnie buforowany dla tego profilu danych. ALE, jeśli proc jest częściej wspólny z bardzo innym zestawem parametrów, plan może nie być odpowiedni. Jest to często nazywane „podsłuchiwaniem parametrów”.
Istnieją sposoby na złagodzenie i wyeliminowanie tego problemu, ale mogą one wymagać kompromisów i zależą od używanej wersji programu SQL Server. Spójrz na OPTIMIZE FOR
i OPTIMIZE FOR UNKNOWN
. JEŚLI (i to jest duże, jeśli) proc jest wywoływana rzadko, ale musi działać tak szybko, jak to możliwe, możesz oznaczyć ją jako OPTION(RECOMPILE)
, aby wymusić ponowną kompilację za każdym razem, gdy zostanie wywołana, ALE nie rób tego dla często wywoływanych procesów LUB bez sprawdzania.
[UWAGA:pamiętaj, które Pakiet serwisowy i aktualizacja zbiorcza (CU) Twój serwer SQL Server 2008 ma, ponieważ logika rekompilacji i podsłuchiwania parametrów działa inaczej w niektórych wersjach]
Uruchom to zapytanie (od Glenn Berry), aby określić stan statystyk:
-- 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);