4

MS SQL Server が を処理する方法に問題があることがわかりましたCROSS APPLY

私が使用しているデータベースには、次のスキーマの価格設定システムがあります。

サービス -> 価格モデル <- 価格コンポーネント ( 「->」はテーブルを指す外部キーを示します)

一部の価格モデルには「段階的価格設定」があります。つまり、金額パラメーターがさまざまなしきい値に達すると、価格が上昇します (1 ~ 3 単位は価格 A、4 ~ 8 単位は価格 B など)。

私が抱えている問題は、INNER JOIN[Price Model ID] の [Service] と [Price Component] の間で重複行が生成されることです。これは、Price Component の価格を実際に使用していないため、表の別のフィールドにすぎないためです。 [Price Component] 行の各行で同じです。

SELECT * 
  FROM [Service] s
 INNER JOIN [Price Component] pc
    ON s.[Price Model Id] = pc.[Price Model Id]

この問題の論理的な修正は、これを行う を に置き換えることINNER JOINですCROSS APPLY

SELECT * 
  FROM [Service] s
 CROSS APPLY (SELECT TOP 1 * 
                FROM [Price Component] pc
               WHERE s.[Price Model Id] = pc.[Price Model Id]
             ) AS pc

問題は、この変更とは一見関係のない他のいくつかの結合で効率が完全に破壊されていることです。実行計画を見ると、以前は 2.3 サイクルかかっていた結合に 480 万サイクルかかっています。

元のクエリに a を追加しようとしましたDISTINCT([Price Component] テーブルからの一意のデータを使用しないため、実行時間が 4 倍になることを除いて、これは関数ソリューションです。必要な値だけを返そうとしました。 [価格コンポーネント] テーブルから、しかしそれはあまり役に立たないようです:

SELECT * 
  FROM [Service] s
 CROSS APPLY (SELECT DISTINCT pc.moneyUnitId 
                FROM [Price Component] pc
               WHERE s.[Price Model Id] = pc.[Price Model Id] 
             ) AS pc

奇妙なことに、CROSS APPLYを anに変更するOUTER APPLYと、他の結合の問題は修正されますが、CROSS APPLY の目的が無効になります (これは、基本的に anINNER JOINと anの違いであると理解していOUTER JOINます)。

での複雑さの異常な増加を引き起こしている可能性があるものについて、誰か考えや洞察を持っていCROSS APPLYますか?

アップデート

したがって、実行計画の解釈方法についてさらに読んだ後、次のことを学びました。

  • 元のクエリ ( INNER JOINs を使用) は、与えられたフィルター データで始まる長い一連の入れ子になったループです。フィルターがインデックス付きフィールドにある限り、応答時間はかなり迅速です。

  • 変更されたクエリ (を使用CROSS APPLY) は、より長い一連のハッシュ マッチであり、指定したすべてのテーブル (フィルターを除く) を結合し、最後にフィルターを適用します。常に死よりも遅い。

  • 変更されたクエリ (を使用OUTER APPLY) を使用すると、元のクエリと同じことを実行できますが、WHERE 句と一致しない結果は除外されません。オリジナルと同じくらいきびきび。

CROSS APPLY問題は、要求されたフィルターの前にすべてのテーブルを結合するように計画を変更するのはなぜですか?

4

3 に答える 3

1

なぜだめですか:

select t1.colA, t3.colX from table1 t1
inner join (select distinct t2.t1FK, t2.colX from table2 t2) t3 on t1.ID = t3.t1FK
于 2012-11-14T17:43:00.977 に答える
0

テーブルのフィールドを1つだけ使用している場合、group byとmax()を使用してレコードをフィルタリングすることを検討したことがありますか?

select a.field1, a.field2, max(b.field3)
from table1 a
join table2 b on a.someid = b.someid
group by a.field1, a.field2
于 2011-10-05T19:54:47.783 に答える
0

実行計画が と の間で同一でない場合JOINCROSS APPLYクエリ オプティマイザーは入れ子になったループ論理演算子を使用しており、状況によってはパフォーマンスに悪影響を及ぼす可能性があります。ネストされたループに関する基本的な情報については、http://msdn.microsoft.com/en-us/library/ms191318(v=sql.90).aspx を参照してください。

于 2011-10-05T15:53:15.897 に答える