【问题标题】:How does a simple CTE work?简单的 CTE 是如何工作的?
【发布时间】:2017-02-17 10:01:06
【问题描述】:

说,我有一个简短的问题。

with test_cte as(
select *
from table1
where conditions1
)
select *
from table2
inner join test_cte
on conditions2
where conditions3

我是否正确假设查询首先通过test_cte 过滤基于conditions1 的行,将数据存储在某处,然后在加入table2 时再次通过test_cte 的剩余行?那么它在哪里存储数据呢?内存?或者这相当于

select *
from table2
inner join table1
on conditions2
where conditions3 and conditions1

但大查询更容易阅读?

【问题讨论】:

  • 将 cte 想象成一个临时表,一旦您使用“表”一次,它就会消失。
  • @Snowlockk - 你是从哪里想到的? CTE 可以用作临时表或内联视图(子查询),优化器将决定哪一个;并且 CTE 不会在使用一次后立即消失。
  • 调用你的 cte 一次然后再调用它。

标签: sql oracle common-table-expression


【解决方案1】:

您的 CTE 只是派生表(Oracle 将其称为内联视图)的语法变体:

select *
from table2
inner join
 (
   select *
   from table1
   where conditions1
 ) AS test_cte
on conditions2
where conditions3

一个体面的优化器并不总是首先创建 CTE/DT 的结果(仅当它太复杂时),所以在您的情况下,计划应该类似于您的第二个查询。只需比较两个查询的计划。

正如您所注意到的,CTE/DT 主要用于通过将更复杂的查询拆分为更小的逻辑组来简化编写更复杂的查询,或者因为您需要一些您无法在单个级别中编写的内容,例如在 a 之上的 Aggregate窗口聚合。

【讨论】:

  • 其实我不认为简化复杂查询是 CTE 的主要用例,至少在 Oracle 中不是。
【解决方案2】:

“那么它在哪里存储数据?RAM?”

这取决于。优化器将评估子查询的成本;如果成本足够高(可能是由于复杂性或大小),那么 Oracle 会将其具体化为全局临时表并将其写入磁盘。因此,只有在这样做有明确的好处时才使用 CTE。

一个好处是我们可以在主查询中多次重复使用 CTE 结果。所以扩展你的例子:

with test_cte as(
    select *
    from table1
    where conditions1
)
select *
from table2
inner join test_cte
    on conditions2
where table1.whatever not in ( select whatever
                               from test_cte
                               where conditions3)

在这里您查询table1 一次但使用它的记录两次。

CTE 的另一个优点是我们可以将它们链接起来:

with test_cte as(
    select *
    from table1
    where conditions1
)
, next_cte as (
   select t1.*
           , t23.*
   from test_cte t1
        join table23 t23
        on t1.id = t23.id)
select * 
from next_cte

这对于将复杂查询分解为更易于理解的块很有用。但是,在开始这条路线之前,确保我们比优化器更聪明对我们来说很重要!

WITH 子句的另一个用途是编写递归查询。从 11gR2 开始,这种结构允许我们在不使用 Oracle 分层查询语法的情况下导航父子关系。 Find out more.

with cte (id, parent_id, lvl) as
     ( select id, p_id, 0 as lvl
       from t23
       where p_id is null
       union all
       select t23.id, t23.p_id, cte.lvl + 1
       from cte
            join t23 
            on cte.id = t23.p_id)
select *
from cte
order by lvl, id
/

【讨论】:

  • 我不认为 CTE 结果集的大小是决定 CTE 是否实现的因素
  • @BobC - 那么你相信什么?我重写了那句话,因为大小不是唯一的因素。优化器评估子查询的成本并决定是否在运行时实现它。我相信结果集的大小是查询成本的一个因素,但我承认我还没有看到关于优化器应用什么规则的明确解释。如果您有链接,请发布它,因为我有兴趣了解更多信息。
  • CTE 转换不是基于成本的。所以基本上,如果你不止一次引用 CTE(或使用 MATERIALIZE 提示),那么它将被物化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
  • 2021-02-26
  • 1970-01-01
  • 2011-02-24
  • 2021-05-22
  • 2013-10-11
  • 2019-11-23
相关资源
最近更新 更多