web-dev-qa-db-ja.com

OPTION FORCE ORDERにより、行が削除されるまでパフォーマンスが向上します

やや複雑な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%を削除するだけで、常にこの問題が発生します。

  1. これは、クエリの推定を完全に不正確にする(したがってクエリの時間を予測できない)ために強制結合順序が正常なのですか?
  2. 次善のクエリパフォーマンスを受け入れる必要があるか、それともタカのように監視してクエリヒントを頻繁に手動で編集する必要があるかを予測する必要がありますか?または、すべての結合についてもヒントがありますか? .3sから2sは大ヒットです。
  3. 行を削除した後にオプティマイザが停止した理由は明らかですか?たとえば、「はい、サンプルスキャンを実行しました。データ履歴の前半でほとんどの行をアーカイブしたため、サンプルはスパースな結果を生成したため、ソートされたハッシュ演算の必要性を過小評価していました」

実行計画を見たい場合は、投稿できる場所を提案してください。そうでなければ、私は最も素晴らしいビットをサンプリングしました。これが根本的な誤推定です。括弧内の数字は(推定:実際の)行です。

                             /  Clustered Index Scan (908:7229)
Nested Loops (Inner Join) --<
                             \  NonClustered Index Seek (1:7229)

内部ループは908行をスキャンすることが期待されていますが、代わりに52,258,441をスキャンしています。正確であれば、このブランチは12秒ではなく、約2ミリ秒で実行されたはずです。行を削除する前に、この内部結合の見積もりは合計係数2だけオフであり、2つのクラスター化インデックスのハッシュ一致として実行されました。

9
shannon

これは、クエリの推定を完全に不正確にする(したがってクエリ時間を予測できない)ために強制結合順序が正常なのですか?

FORCE ORDERを使用しても、推定値が不正確になることはありません。テーブルの統計を強制的に更新すると、推定精度が向上する場合があります。

次善のクエリパフォーマンスを受け入れる必要があるか、それともタカのように監視してクエリヒントを頻繁に手動で編集する必要があるかを予測する必要がありますか?または、すべての結合についてもヒントがありますか? .3sから2sは大ヒットです。

FORCE ORDERヒントを使用せずに、最適化計画に最適な計画を生成するために必要な情報が提供されるようにすることが望ましいでしょう。そうすることで、手動による介入を必要とせずに、基礎となるデータ分散への変更をより適切に処理する必要があります。ただし、データの性質により、カーディナリティが1時間ごとまたは1日ごとに大幅に変化する可能性がある場合は、 計画ガイド を使用して計画が確実に修正されるようにすることを検討してください。

行を削除した後にオプティマイザが停止した理由は明らかですか?たとえば、「はい、サンプルスキャンを実行しました。データ履歴の前半でほとんどの行をアーカイブしたため、サンプルはスパースな結果を生成したため、ソートされたハッシュ演算の必要性を過小評価していました」

問題のあるテーブルの行数については言及しませんでしたが、削除によって次のいずれかになる可能性があります。

  • 統計の更新をトリガーするのに十分な行を削除しませんでした。これは、行の20%が変更されたときに発生するはずですが、動的しきい値を有効にするために トレースフラグ2371 を使用するオプションがあります。
  • 統計の更新をトリガーしましたが、収集されたサンプルは代表的なものではありませんでした。これを修正するには、手動更新 WITH FULLSCAN を実行します。

また、古き良き パラメータスニッフィング の問題が発生している可能性があります。この問題には、無数のオプションがあります。 WITH RECOMPILE クエリでこれほど大きな値を指定するのはコストがかかるオプションですが、プロシージャレベルとステートメントレベルの両方で調査する価値があります。

6