Sql 我如何决定是否应该使用CTE?

Sql 我如何决定是否应该使用CTE?,sql,database,sql-server-2008,tsql,common-table-expression,Sql,Database,Sql Server 2008,Tsql,Common Table Expression,请容忍我,我是新手 我的问题是-我应该什么时候使用CTE?我如何决定是否使用CTE 我应该在什么时候使用这个: ;with cteTesting as ( select * from testing.first_table ) select * from testing.second_table s inner join cteTesting t on s.key = t.key 在这方面: select * from

请容忍我,我是新手

我的问题是-我应该什么时候使用CTE?我如何决定是否使用CTE

我应该在什么时候使用这个:

;with cteTesting as
(
    select  *
    from    testing.first_table
)
select  *
from    testing.second_table s
        inner join cteTesting t
            on s.key = t.key
在这方面:

select  *
from    testing.second_table s
        inner join
        (
            select  *
            from    testing.first_table
        ) t
        on s.key = t.key
为什么?这仅仅是为了代码流、代码可读性,还是有更技术性的东西?在某些情况下,是否会产生更好的执行计划

编辑:刚刚意识到我的示例代码示例非常糟糕。我想强调的是,在很多情况下,我可以在from语句中使用select而不是CTE-我如何决定应该使用哪一个?

我个人认为CTE版本更具可读性,尤其是当select变得更大时

当您在主选择中多次使用派生表时,最好使用CTE,因为它告诉数据库您只想运行一次。尽管如果优化器足够聪明,能够在from子句中检测到两个相同的子选择并只运行一次,我也不会感到惊讶:

with foo as (
   select ..
   from bar
)
select f1.*
from foo f1 
  join foo f2 on ...
vs


我认为最重要的部分是保持一致性(在你所写的内容和团队内部)。

对于简单的例子,这没有多大区别。如果您需要使用这些功能来构建层次结构,那么您没有太多选择—您需要使用CTE

另一种情况是,当您需要多次连接同一子查询时,它可能不会对性能产生太大影响,但对可读性有影响。如果使用子查询,则必须重复整个表达式,而对于CTE,只需使用名称两次:

;With NamedExpression as (
    select t1.ID,t2.ID as ID2,SUM(t3.Value) as Val
    from
      Table1 t1
        left join
      Table2 t2 on t1.id = t2.t1id
         inner join
      Table3 t3 on t3.col = t1.id or t3.col2 = t2.id
    group by
      t1.ID,t2.ID
)
select
    *
from
    NamedExpression ne
        inner join
    NamedExpression ne2
        on
            ne.ID2 = ne2.ID

还应该注意的是,如果您作为子查询执行上述操作,并且表达式特别复杂,读者/维护人员有时可能需要时间来验证这两个子查询实际上是相同的,并且这两个子查询之间没有细微的差异


此外,如果缩进样式表示子查询应显示在其封闭查询的右侧,则构建在其他表达式上的表达式可能会导致所有代码向右移动,而对于CTE,则在构建每个子表达式(CTE)时会停止并移回左侧:

vs:

我注意到,当涉及大型数据集时,连接(特别是与许多WHERE子句结合使用时)可能会产生灾难性的性能

CTE可以通过仅选择相关记录并连接这些子集来解决此问题


将CTE视为一种预选择,为最终选择准备数据。

我使用CTE的另一个原因不是替换派生表,而是确保复杂的报表SQL包含正确的记录。因此,假设您正在做某种类型的财务报告,并且希望确保返回的记录完全符合您的要求。当您有10个联接时,很难判断数据是否正确

因此,我使用CTE构建了一个复杂的查询。例如,我只希望订单符合某些标准。第一个CTE就是挑选这些的那个。我编写它,然后在CTE上运行select。这会告诉我我的basline订单数量,这样当我增加复杂性时,我可以立即看到该数量在哪里更改,并确定它是否应该更改,或者是否需要更改查询。这让我可以相当快地知道是否需要左连接或内部连接,或者是否需要相关表上的条件将其限制为一条记录

通常,当我这样做时,我会在到达最终选择之前链接CTE,这要简单得多。这一点的进一步价值在于,我发现,当需要更改这些复杂的报告查询时,维护它们要容易得多。假设我有一个链中的CTE,如:

  • 命令
  • 费用汇总表
  • 客户人口统计

然后,当我需要更改成本计算方法时,既可以更容易地找到进行更改的位置,也可以更容易地检查最终结果。

Hmn。值得深思。谢谢你的精心设计,谢谢。我们将对此进行更深入的探讨,但这似乎是选择CTESQL服务器的一个非常有说服力的原因。通常情况下,即使是同一个CTE,也不会重复引用一次,更不用说在不同的派生表中查找公共子表达式了。@MartinSmith:非常遗憾,谢谢您提供的信息。我认为SQL Server优化器至少与Oracle或PostgreSQL中的优化器一样聪明。
;With NamedExpression as (
    select t1.ID,t2.ID as ID2,SUM(t3.Value) as Val
    from
      Table1 t1
        left join
      Table2 t2 on t1.id = t2.t1id
         inner join
      Table3 t3 on t3.col = t1.id or t3.col2 = t2.id
    group by
      t1.ID,t2.ID
)
select
    *
from
    NamedExpression ne
        inner join
    NamedExpression ne2
        on
            ne.ID2 = ne2.ID
;WITH CTE1 AS (
    SELECT
    ...
), CTE2 as (
    SELECT
    ...
    FROM CTE1
), CTE3 as (
    SELECT
    ...
    FROM CTE2
)
select * from CTE3
select *
from
   (
        select ...
        from
             (
                 select ...
                 from
                     (
                          select ...