SQL Server のクエリ実行プランでは、使用されているインデックスの「実際の行数」が間違っていることが示され、パフォーマンスが非常に遅い
-
03-07-2019 - |
質問
今日、互換性レベル 80 (SQL2000) で実行されているデータベース内の SQL Server 2005 SP2 で実行されているストアド プロシージャで、興味深いパフォーマンスの問題に遭遇しました。
プロシージャは約 8 分間実行され、実行プランには、実際の行数 1.339.241.423 のインデックスの使用状況が示されています。これは、正しく示されているテーブル自体の「実際の」実際の行数 1.144.640 よりも約 1000 倍大きいです。推定行数による。したがって、クエリ プラン オプティマイザーによって与えられる実際の行数は明らかに間違っています。
興味深いことに、proc 内の procs パラメータ値をローカル変数にコピーし、そのローカル変数を実際のクエリで使用すると、すべてが正常に動作します。proc は 18 秒で実行され、実行プランには正しい実際の行数が表示されます。
編集: TrickyNixon が示唆しているように、これはパラメーター スニッフィングの問題の兆候であるようです。しかし実際には、どちらの場合もまったく同じ実行計画が得られます。同じインデックスが同じ順序で使用されています。私が見た唯一の違いは、パラメーター値を直接使用したときに PK_ED_Transitions インデックスの実際の行数が増加する方法です。
dbcc dbreindex と UPDATE STATISTICS をすでに実行しましたが、成功しませんでした。dbcc show_statistics では、インデックスの適切なデータも表示されます。
プロシージャは RECOMPILE を使用して作成されるため、実行されるたびに新しい実行プランがコンパイルされます。
より具体的に言うと、これは高速に実行されます。
CREATE Proc [dbo].[myProc](
@Param datetime
)
WITH RECOMPILE
as
set nocount on
declare @local datetime
set @local = @Param
select
some columns
from
table1
where
column = @local
group by
some other columns
そして、このバージョンの実行は非常に遅いですが、(使用されているインデックスの実際の行数が多すぎることを除けば) まったく同じ実行プランが生成されます。
CREATE Proc [dbo].[myProc](
@Param datetime
)
WITH RECOMPILE
as
set nocount on
select
some columns
from
table1
where
column = @Param
group by
some other columns
何か案は?SQL Server がクエリ プランを計算するときに実際の行数の値をどこから取得するかを知っている人はいますか?
アップデート:copat モードを 90 (Sql2005) に設定した別のサーバーでクエリを試してみました。それと同じ動作です。これはバグのような気がするので、MS サポートに電話してみようと思います。
解決
わかりました、ついに自分でやってきました。
2つのクエリプランは、最初は見落としていた細かい点で異なります。遅いものは、ネストされたループ演算子を使用して、2つのサブクエリを結合します。そして、その結果、インデックススキャン演算子の現在の行数が多くなります。これは、単に入力aの行数と入力bの行数を乗算した結果です。
この場合、オプティマイザーが1000タイマーを高速に実行するハッシュマッチの代わりにネストされたループを使用することを決定する理由はまだわかりませんが、新しいインデックスを作成することで問題を処理できます。ネストされたループでのインデックススキャンの代わりに、インデックスシークstatt。
他のヒント
ストアドプロシージャの実行プランをコピー/貼り付けクエリに対してチェックする場合、推定プランと実際のプランのどちらを使用していますか? [クエリ]、[実行プランを含める]の順にクリックしてから、各クエリを実行してください。それらの計画を比較して、違いを確認してください。
パラメータスニッフィングの場合のように聞こえます。考えられる解決策とともに優れた説明を次に示します。パラメーターの匂いを嗅ぎます!
これに対処する別のStackOverflowスレッド:パラメータスニッフィング(またはスプーフィング)in SQL Server
私には、統計が間違っているように聞こえます。インデックスを再構築しても、必ずしも更新されるわけではありません。
影響を受けたテーブルに対してすでに明示的な UPDATE STATISTICS
を試しましたか?
走ったことがありますか sp_spaceused SQL Server がそのテーブルの正しい概要を取得しているかどうかを確認するには?SQL 2000 では、エンジンは実行プランを構築するときにその種のメタデータを使用していたと思います。以前は走らなければならなかった DBCC 更新の使用法 SQL Server が間違った行数データのために間違ったインデックスを選択していたため、急速に変化する一部のテーブルのメタデータを毎週更新しました。
SQL 2005 を実行していて、BOL によれば、2005 では UpdateUsage を実行する必要はなくなっていますが、2000 互換モードなので、依然として UpdateUsage が必要であることがわかるかもしれません。