web-dev-qa-db-ja.com

多くの外部キーを使用したカスケード削除のパフォーマンスチューニング

時間がかかる削除クエリがあります。実行プランを見ると、削除クエリの推定コストのほとんどは、データモデルの、大量のデータ(たとえば、40万行)に問題がないように見えるセクションにありますが、1つのことを理解できません。

データモデルのストリップビュー:

table ParentObject 
      int parentObjectId (PK)

table Child
      int childId (PK)
      int parentId (FK)
      <stuff>

table GrandChild
      int grandChildId (PK)
      int childId (FK)
      <more stuff>

親オブジェクトに200,000の子があり、子に2つほどのGrandChildrenがある場合。以下のパフォーマンスの調整に興味があります。

DELETE FROM ParentObject WHERE parentObjectId = %d;

孫では、(childId、+ 2つの列)に追加の非クラスター化インデックスと主キーインデックスがあります。子には、追加の非クラスター化一意インデックスがあります(parentId、+ 2つの列)。

クエリプランで見たのは、孫オブジェクトの削除中に、2つの高価な並べ替え操作が削除と混在していたため、なぜそれらが存在するのか理解できません。

この削除操作を高速化するために何を見るべきですか?並べ替える必要がありますか? IDを非正規化し、親IDを孫テーブルに追加した場合、役に立ちますか?私は愚かに私のインデックスを構築しましたか?

完全な実行計画はこちら

6
Mikeb

主な質問に直接答えるために、ソートは、インデックスキーの順序で演算子を更新する(この場合は削除を実行する)行を表示するためにあります。ここで機能する原則は、キーでのソートにより、インデックスへの順次アクセスが促進されることです。

詳細はハードウェア、影響を受けるページがメモリにある可能性、およびそれらに割り当てられたメモリ内でソートが完了するかどうかによって異なりますが、これは適切な最適化になります。オプティマイザが、順次インデックスアクセスに関連する効率の向上によってソートのコストが返済されると判断すると、更新演算子にプロパティDMLRequestSortを設定します。

DML Request Sort

オプティマイザーは、クラスター化インデックス(またはヒープ)を維持するために更新を個別のオペレーターに分割し、非クラスター化インデックスを維持することも決定します。多くの場合、最初にクラスター化インデックスキーに対して、次に再度非クラスター化インデックスに対して、複数回ソートすることを決定します。繰り返しになりますが、ソートが最適であると見なされる場合、各インデックス更新演算子はDMLRequestSortプロパティをtrueに設定します。

つまり、最初に修正することは、フィードする結合演算子がネストされたループ結合であるインデックススキャンを排除し、熱心なインデックススプールを削除します。これは、クエリが実行されるたびに 空のインデックスに行を挿入する です。多くの場合、熱心なインデックススプールは、有用な永続インデックスがないことを示す最も明確な兆候です。インデックススプールオペレータのシーク述語は、オプティマイザがインデックスを要求するキーを識別します。

非クラスター化インデックスが欠落している(熱心なインデックススプールが必要)テーブルの例は次のとおりです。

child6gc8Selections
gc9s
child7s
gc6s

eager index spools

ネストされたループ結合の下で現在スキャンされているテーブルの例は次のとおりです。

child1
parentObjectMessages
child8s
child7s
child6s
child5s
child4s
child3s
child2s

scan below nested loops

上記の例では、クラスター化インデックススキャンの出力リストはId, parentObjectId、入れ子ループ結合述語はchild7s.parentObjectId = parentObject.Id、結合出力列リストはchild7s.Idです。

その情報から、クエリのこの部分のchild7sに対する適切なアクセス方法(インデックス)は、parentObjectIdをキーとして、Idをインクルード列として指定することになります。これを既存のインデックス作成戦略に組み込むための最善の方法を理解できるはずです。

以下は、オプティマイザが現在ハッシュ結合を選択しているテーブルの例です。このようなテーブルをチェックして、それが適切なアクセス方法であることを確認します。

child6gc8Selections
gc2s
gc5s
gc6Properties

hash joins

テーブルchild2bigChildは、明示的なソートが必要なマージ結合にも参加しています。繰り返しますが、この種の問題を回避できるかどうかを確認します。

sort before merge

基本的なインデックス作成の問題が解決したら、必要に応じて他の最適化を確認できます。

15
Paul White 9