やや複雑なSQL Server 2008クエリ(約200行のかなり高密度のSQL)があり、必要なときに実行されませんでした。時間の経過とともに、パフォーマンスは約0.5秒から約2秒に低下しました。
実行計画を見ると、結合を並べ替えることでパフォーマンスが向上することは明らかでした。私はそうしました、そしてそれは...約0.3秒にまで減少しました。これで、クエリに「OPTION FORCE ORDER」というヒントが追加されました。
今日、私はデータベースをクリーンアップします。行の約20%をアーカイブし、行を削除する以外は関連するデータベースでアクションを実行しません...実行プランは完全にホースされます。特定のサブツリーが返す行数を完全に誤って判断し、(たとえば)次のものを置き換えます。
<Hash>
と
<NestedLoops Optimized='false' WithUnorderedPrefetch='true'>
これで、クエリ時間が約0.3秒から約18秒に急上昇します。(!)行を削除したからといって。クエリヒントを削除すると、クエリ時間は約2秒に戻ります。良いが悪い。
データベースを複数の場所とサーバーに復元した後、問題を再現しました。各テーブルから行の約20%を削除するだけで、常にこの問題が発生します。
- 強制結合順序がクエリの見積もりを完全に不正確にする(したがってクエリの時間を予測できない)のは、これが正常ですか?
- 最適ではないクエリのパフォーマンスを受け入れる必要があるか、それともタカのように見て、頻繁に手動でクエリのヒントを編集する必要があると思いますか?または、すべての結合についてもヒントがありますか?.3sから2sは大ヒットです。
- 行を削除した後にオプティマイザが停止した理由は明らかですか?たとえば、「はい、サンプルスキャンを実行しました。データ履歴の前半でほとんどの行をアーカイブしたため、サンプルはスパースな結果を生成したため、ソートされたハッシュ演算の必要性を過小評価していました」
実行計画を見たい場合は、投稿できる場所を提案してください。そうでなければ、私は最も素晴らしいビットをサンプリングしました。これが根本的な誤推定です。括弧内の数字は(推定:実際の)行です。
/ Clustered Index Scan (908:7229)
Nested Loops (Inner Join) --<
\ NonClustered Index Seek (1:7229)
内部ループは908行をスキャンすると予想されますが、代わりに52,258,441をスキャンすることに注意してください。正確であれば、このブランチは12秒ではなく、約2ミリ秒で実行されたはずです。行を削除する前に、この内部結合の推定は合計係数2だけオフであり、2つのクラスター化インデックスのハッシュ一致として実行されました。