説明している動作は、多くの場合、誤ってキャッシュされたクエリプランや古い統計が原因です。
これは通常、WHERE句に多数のパラメーターがある場合、特に次の形式のパラメーターの長いリストがある場合に発生します。
(@parameter1 is NULL OR TableColumn1 = @parameter1)
たとえば、キャッシュされたクエリプランの有効期限が切れ、代表的でないパラメータのセットを使用してprocが呼び出されたとします。次に、このデータプロファイルのプランがキャッシュされます。ただし、procが非常に異なるパラメータのセットでより頻繁に一般的である場合、計画は適切でない可能性があります。これは「パラメータスニッフィング」としてよく知られています。
この問題を軽減および排除する方法はいくつかありますが、トレードオフが必要になる場合があり、SQLServerのバージョンによって異なります。 OPTIMIZE FOR
をご覧ください
およびOPTIMIZE FOR UNKNOWN
。 procが頻繁に呼び出されないが、できるだけ速く実行する必要がある場合は、 OPTION(RECOMPILE)
、呼び出されるたびに再コンパイルを強制するために、ただし、頻繁に呼び出されるprocに対して、または調査せずにこれを実行しないでください。
[注:サービスパックと累積的な更新(CU) SQL Server 2008ボックスには、再コンパイルとパラメータスニッフィングロジックの動作がバージョンによって異なるため、あります]
このクエリを(Glenn Berryから)実行して、統計の状態を判別します。
-- 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);