公共表表达式 (CTE) 的好处?

Roy*_*mir 21 sql-server cte

msdn

与派生表不同,CTE 可以是自引用的,并且可以在同一个查询中多次引用。

我经常使用 CTE,但我从未深入思考使用它们的好处。

如果我在同一个查询中多次引用 CTE:

  • 是否有任何性能优势?
  • 如果我进行自联接,SQL Server 会扫描目标表两次吗?

JNK*_*JNK 25

通常,CTE 永远不会提高性能

CTE 本质上是一种一次性视图。没有存储额外的统计信息,没有索引等。它用作子查询的简写。

在我看来,它们很容易被过度使用(我在我的工作中看到很多代码过度使用)。 这里有一些很好的答案,但是如果您需要多次引用某些内容,或者它超过几十万行,请将其放入#temp表中并对其进行索引。

  • 同意。除了递归 CTE,它们只是帮助提高可读性 (3认同)
  • @a_horse_with_no_name - 这相当于将其设为子查询。如果结果在单个查询中多次使用,它将被重用而不是重新计算。如果它在多个查询中使用,那么`CTE` 是一个糟糕的选择,因为在第一次查询后结果被丢弃。 (2认同)

HLG*_*GEM 14

除了递归,我发现 CTE 非常有用的一个地方是在创建复杂的报告查询时。我使用一系列 CTE 来获取我需要的数据块,然后在最终选择中组合。我发现它们比使用大量派生表或 20 个连接做同样的事情更容易维护,而且我发现我可以更确定它返回正确的数据,而不会由于其中的一对多关系而影响多条记录所有不同的连接。让我举一个简单的例子:

;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
Run Code Online (Sandbox Code Playgroud)

因此,通过分离出您想要的不同信息块,您可以单独检查每个部分(使用注释掉的选择,通过单独取消每个部分的注释并且仅在该选择范围内运行)以及是否需要对费用进行更改计算(在本例中),比将它们全部混合成一个庞大的查询更容易找到。当然,我使用它的实际报告查询通常比示例复杂得多。