web-dev-qa-db-ja.com

Common Table Expression(CTE)のメリットは?

From msdn

派生テーブルとは異なり、CTEは自己参照することができ、同じクエリで複数回参照できます。

私はCTEをかなり使用していますが、CTEを使用することの利点について深く考えたことはありません。

同じクエリでCTEを複数回参照した場合:

  • パフォーマンス上のメリットはありますか?
  • 自己結合を実行している場合、SQL Serverはターゲットテーブルを2回スキャンしますか?
21
Royi Namir

原則として、CTEによってパフォーマンスが向上することは決してありません

CTEは本質的に使い捨てのビューです。保存されている追加の統計、インデックスなどはありません。サブクエリの省略形として機能します。

私の意見では、それらは簡単に使い過ぎる可能性があります(私の仕事では、コードの中で多くの使いすぎが見られます)。 いくつかの良い答えがここにあります しかし、何かを複数回参照する必要がある場合、またはそれが数十万行を超える場合は、#tempテーブルの代わりにインデックスを付けます。

25
JNK

再帰以外に、CTEが非常に役立つと思うのは、複雑なレポートクエリを作成するときです。一連のCTEを使用して必要なデータのチャンクを取得し、最終的な選択で結合します。多くの派生テーブルまたは20の結合で同じことを行うよりも維持が簡単であることがわかり、1対多の関係により複数のレコードの影響なしに正しいデータを返すことがより確実になることがわかりましたすべての異なる結合。簡単な例を挙げましょう。

;WITH Conferences (Conference_id)
AS 
(select  m.Conference_id
FROM mydb.dbo.Conference m 
WHERE client_id = 10
    and Conference_id in 
            (select Conference_id from mydb.dbo.Expense 
            where amount <>0
            and amount is not null)
     )
--select * from Conferences
,MealEaters(NumberMealEaters, Conference_id, AttendeeType)
AS
(Select count(*) as NumberMealEaters, m.Conference_id,  AttendeeType 
from mydb.dbo.attendance ma 
join Conferences m on m.Conference_id = ma.Conference_id
where (ma.meals_consumed>0 or meals_consumed is null)and attended = 1
group by m.Conference_id)
--select * from MealEaters

,Expenses (Conference_id,expense_date, expenseDescription,  RecordIdentifier,amount)
AS
(select Conference_id,max(expense_date) as Expense_date, expenseDescription,  RecordIdentifier,sum(amount) as amount
    FROM
        (SELECT Conference_id,expense_date,  amount, RecordIdentifier
        FROM mydb.dbo.Expense
        WHERE  amount <> 0 
            and Conference_id IN 
            (SELECT  Conference_id
            FROM mydb.dbo.Conferences ) 
        group by Conference_id, RecordIdentifier) a
)
--select * from Expenses
Select m.Conference_id,me.NumberMealEaters, me.AttendeeType, e.expense_date,         e.RecordIdentifier,amount
from Conferences m
join mealeaters me on m.Conference_id = me.Conference_id
join expenses e on e.Conference_id = m.Conference_id

したがって、必要な情報のチャンクを分離することで、各部分を個別にチェックできます(コメント化された選択を使用して、各部分のコメントを解除し、その選択までのみ実行します)。費用を変更する必要がある場合計算(この例では)は、1つの大規模なクエリにすべてが混在している場合よりも簡単に見つけることができます。もちろん、これを使用する実際のレポートクエリは、通常、例よりもはるかに複雑です。

14
HLGEM

いつものように異なりますが、パフォーマンスが大幅に向上する場合があります。選択にCTEを使用し、それをINSERT INTOで使用するINSERT INTO SELECTステートメントでそれがわかります。データベースでRCSIがオンに設定されている必要があるかもしれませんが、選択されている時間が非常に少ない場合は、かなり役立ちます。

0
Ron S