web-dev-qa-db-ja.com

外部適用と左結合のパフォーマンス

SQL SERVER 2008 R2を使用しています

SQLでAPPLYに出会ったばかりで、それが非常に多くのケースでクエリの問題を解決する方法を気に入っていました。

結果を得るために2つの左結合を使用していたテーブルの多くは、1つの外部適用で取得できました。

ローカルDBテーブルに少量のデータがあり、展開後、コードは少なくとも20倍大きなデータで実行されることになっています。

大量のデータの場合、外側の適用が左の2つの結合条件よりも長くかかる可能性があることを懸念しています。

適用がどのように正確に機能し、非常に大きなデータのパフォーマンスにどのように影響するかを誰かに教えてください1。

これは、2つの左結合を使用したクエリです。

select EC.*,DPD.* from Table1 eC left join
  (
   select member_id,parent_gid,child_gid,LOB,group_gid,MAX(table2_sid) mdsid from Table2
   group by member_id,parent_gid,child_gid,LOB,group_gid

  ) DPD2 on DPD2.parent_gid = Ec.parent_gid
        AND DPD2.child_gid = EC.child_gid
        AND DPD2.member_id = EC.member_id
        AND DPD2.LOB = EC.default_lob
        AND DPD2.group_gid = EC.group_gid
  left join
  Table2 dpd on dpd.parent_gid = dpd2.parent_gid 
            and dpd.child_gid = dpd2.child_gid
            and dpd.member_id = dpd2.member_id 
            and dpd.group_gid = dpd2.group_gid 
            and dpd.LOB = dpd2.LOB
            and dpd.table2_sid = dpd2.mdsid

これは外部適用のクエリです

select * from Table1 ec   
OUTER APPLY (
      select top 1 grace_begin_date,retroactive_begin_date,Isretroactive
                    from Table2 DPD 
                    where DPD.parent_gid = Ec.parent_gid
                    AND DPD.child_gid = EC.child_gid
                    AND DPD.member_id = EC.member_id
                    AND DPD.LOB = EC.default_lob
                    AND DPD.group_gid = EC.group_gid
                    order by DPD.table2_sid desc
     ) DPD 
38

誰でも正確に適用がどのように機能し、非常に大きなデータのパフォーマンスにどのように影響するか教えてくれますか

APPLY相関結合 です(一部の製品およびSQL標準の新しいバージョンでは_LATERAL JOIN_と呼ばれます)。他の論理構造と同様に、パフォーマンスに直接影響を与えることはありません。原則として、論理的に同等の構文を使用してクエリを記述でき、オプティマイザは入力をまったく同じ物理的な実行プランに変換します。

もちろん、これにはオプティマイザがすべての可能な変換を把握し、それぞれを検討する時間が必要です。このプロセスには現在の宇宙時代よりも時間がかかる可能性があるため、ほとんどの商用製品はこのアプローチを採用していません。したがって、クエリ構文は最終的なパフォーマンスに影響を与える可能性があり、実際に影響を及ぼしますが、どちらがより良いのか、なぜであるのかについての一般的な記述を行うことは困難です。

オプティマイザにはこのパターンを同等のJOINに変換するロジックが含まれていないため、OUTER APPLY ( SELECT TOP ... )の特定の形式は、SQL Serverの現在のバージョンで相関ネストループ結合になる可能性が最も高くなります。外部入力が大きく、内部入力がインデックス付けされていない場合、または必要なページがまだメモリにない場合、相関のあるネストされたループ結合はうまく機能しない可能性があります。さらに、オプティマイザのコストモデルの特定の要素は、相関するネストされたループ結合が、意味的に同一のJOINよりも並列実行計画を生成する可能性が低いことを意味します。

単一の左結合とrow_number()で同じクエリを作成することができました

これは、一般的なケースではより良い場合とそうでない場合があります。代表的なデータを使用して、両方の選択肢をパフォーマンステストする必要があります。 _LEFT JOIN_および_ROW_NUMBER_の方が効率的である可能性は確かにありますが、選択した正確なクエリプランの形状によって異なります。このアプローチの効率に影響を与える主な要因は、必要な列をカバーし、_PARTITION BY_および_ORDER BY_句で必要な順序を提供するインデックスの可用性です。 2番目の要素は、テーブルのサイズです。クエリが関連するテーブルの比較的小さな部分に触れる場合、効率的で適切にインデックス付けされたAPPLYは、最適なインデックス付けで_ROW_NUMBER_よりも優れたパフォーマンスを発揮します。テストが必要です。

46
Paul White 9

最初のクエリは、SQLサーバーへの1つの要求だけで並列実行できます。すべてのレコードをフェッチし、フィルター基準に基づいて出力を提供します。

ただし、2番目の場合は行ごとに実行され、各行についてTable2がスキャンされ、結果に追加されます。

外部クエリのレコード数が少ない場合は、2番目のクエリの方が適切です(外部適用)。ただし、最初のクエリでより多くのデータを取得できる場合は、最初のクエリを使用する必要があります。

3
user55424