web-dev-qa-db-ja.com

クエリのヒント?マージで重複排除されたCTEの場合

このリンクを参照してください: MERGEステートメントのパフォーマンスの最適化

理想的なパフォーマンスのために、次の基準が与えられています。

  • ソーステーブルの結合列に、一意でカバーするインデックスを作成します。
  • ターゲットテーブルの結合列に一意のクラスター化インデックスを作成します。

定期的に100万から500万の行をマージする大きなテーブル(1億行以上)がたくさんあります。ターゲットテーブルには一意のクラスター化インデックスがあり、ソーステーブルのキーと一致し、2番目の基準を満たしています。

時間の経過とともにソーステーブルにデータを入力する一括インポートプロセスがあります。次に、マージの準備として、non-uniqueクラスター化インデックスを配置します-これは、重複する値が挿入されないようにする方法がないためですバルクプロセス中。これは半分だけが最初の基準を満たします。

マージのソースとして重複排除ロジックを備えたCTEを使用しています-

...
USING
    ( SELECT
        cte.Key1,
        cte.Key2,
        cte.Key3,
        cte.RestOfTheColumns
      FROM
        ( SELECT 
           Key1,
           Key2,
           Key3,
           RestOfTheColumns,
          ,ROW_NUMBER() OVER (PARTITION BY Key1, Key2, Key3 ORDER BY Key1, Key2, Key3) AS RowNumber
        ) cte
      WHERE cte.RowNumber = 1
    ) 
...

理想的には、これは一意にインデックス付けされたテーブルにすでに存在していると思います。

要約すれば:

  • クラスター化されたインデックスをソースに配置し、クエリ内で重複排除します。
  • クエリアナライザでは、クラスタ化されたインデックスのマージは計画コストの91.9%を占めます。

CTE /基礎となるテーブルに明示的な一意の制約がないことは重要ですか?重複はありませんが、SQLはそれを認識していないため、アップサートのすべての行をチェックすると思います。

1
lucrativelucas

CTEがクエリを実行しているテーブルに(Key1、Key2、Key3、...)で始まるクラスター化(またはカバー)インデックスがある場合、これはパフォーマンスの高いクエリである必要があります。

ソーステーブルの「Key4」(できればID列)を一意でないクラスター化インデックスに追加して、インデックスを一意にすることができますか?そうすれば、ROW_NUMBER()の_ORDER BY_として「Key4」を設定することもできます。これかもしれないパフォーマンスを改善しますが、それは単なる推測です。

Clustered Index Merge演算子がプランの90%を超えているという事実は、それ自体がパフォーマンスの問題を示しているわけではなく、結合以外にクエリプランで行うことはそれほど多くないことを示しています。実際、十分に最適化された計画があることを示している可能性があります。適切なインデックスがある場合、ROW_NUMBER()は非常に効率的です。

2