web-dev-qa-db-ja.com

インラインサブクエリよりもクロスアプライまたはCTEを使用する利点がない

私はこのようなクエリに出くわしました:

SELECT (SELECT COUNT(1) FROM Orders o WHERE i.ItemId = o.ItemId) [C]
FROM Items i

次のように変更しました

;WITH cte_count
AS
(
    SELECT COUNT(1) c, OrderId FROM Orders Group By ItemId
)
SELECT a.c [Count], i.Name
FROM Items i
INNER JOIN cte_count c ON (c.ItemId = i.ItemId)

ただし、両方の実行計画は以下に示すものと同じです。

CTE and Inline Execution Plan

同様に、TOP 1 Order By Idを選択する別のクエリがありました。これをCROSS APPLYに移動してみましたが、これについても同じ実行計画を取得しました。

Cross Apply and Inline Execution Plan

もちろん、クエリには他の結合と列がありました。

私のジレンマは、CROSS APPLYCTEを使用することの有用性と利点についてです。エキゾチックなものはありますか?

8
TheVillageIdiot

しかし、両方の実行プランは以下に示すものと同じです:

計画は異なります。 1つは内部結合で、もう1つは外部結合です。単純なテストでは結果は同じかもしれませんが、セマンティクスは異なります。より複雑なクエリでは、その違いにより実行プランが明らかに異なり、パフォーマンスに影響を与える可能性があります。

SQLで同じ要件(または例のように類似の要件)を表現するには、通常、多くの方法があります。どちらを使用するかは、最初は好みとスタイルの問題です。場合によっては、宣言型SQLはオプティマイザを介して異なるコードパスを使用するため、どちらか一方を使用すると、パフォーマンスに重要な違いが生じます。この特定のケースでは、外部結合は、オプティマイザーの探索機能とうまく機能しない可能性があります(内部結合よりも外部結合で使用するツールが少なくなります)。

異なる構文を使用してsame結果を定義するようにクエリを書き換えることは、有効なチューニング方法である可能性がありますが、SQL Serverにパッチを適用するときは常に細部に注意を払い、再テストする必要がありますまたはアップグレード。一般に、SQLで要件を表現する1つの方法を他の方法よりも優先する理由はありません。

さらに、Andriyが質問の他のコピーの comment で述べたように、「より一般的なケースでは、インラインクエリでは、CTE( CTEである必要はありません。通常の副選択である場合もあります)または行セットをCROSS APPLYすると、複数の列にアクセスできるようになります。」

21
Paul White 9

私のジレンマは、CROSS APPLYとCTEを使用することの有用性と利点です。エキゾチックなものはありますか?

小規模なデータセットの場合、オプティマイザはおそらく広範な分析に悩まされることはありません。ただし、大規模なデータセット(例では数百万の注文やアイテム)の競合する計画を検討する場合、特にアイテムにインデックスが付けられている場合、CROSS APPLYはより速く実行されます。

また、実行計画を使ってこのようにチェックするのも適切です。

承知しました。違いがあるとすれば、計画は示されていただろう。さらに、実行時にパフォーマンスの違いに気付くでしょう。

1
Emacs User

もしあなたがやれば

SELECT i.Name
       COUNT(o.OrderId) c
FROM   Items i
       JOIN Orders o ON i.ItemID = o.ItemID
GROUP BY i.ItemID

cteapplyには、いくつかのケースで利点があると確信していますが、おそらくこのような単純なケースではありません

cteを使用したいのは、最終的なクエリを作成し、再帰コースを作成するために、大きな結果を小さな結果に分解する方法の視覚的なフローを作成しようとするときに、主に美的理由からです。

applyは、前のテーブルからparam値を取得するテーブル値関数を使用している場合に非常に便利です。 cross applyは、full joinステートメントよりもきれいにできます。

クエリプランで探しているものがわかっている場合は、好みの問題だと思います

0
JamieD77