【问题标题】:Is CTE really a view?CTE真的是一种观点吗?
【发布时间】:2017-04-25 18:49:10
【问题描述】:

我一直认为 CTE 应该被视为内联视图宏。所以我的想法是:如果 CTE 没有被引用/使用,它就不会被执行。这只是一个定义,仅此而已。

但是,请执行以下查询:

create table t
(
    id int primary key
);

with
a as
(
    insert into t(id) values(1)
)
select false;

select * from t;

似乎在基于 CTE 的查询之后,select * from t 返回插入到 CTE 中的元组。尽管没有使用 CTE,为什么还要插入这个元组?

这是设计还是规范?依赖这种行为是否安全?这允许在一个查询中执行多个完全不相关的查询。

这似乎与以下信息相矛盾:https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/#comment-19121

【问题讨论】:

  • 您可以在 CTE 中使用 INSERT 吗?我相当肯定你只能使用SELECT 语句。
  • @Dstanley 是的,你可以。我一直在做INSERTDELETEUPDATE 没有问题。唯一的区别是我总是提到 CTE,因为它使用 RETURNING ...,但不是在这个问题中。
  • 你能发布一个实际的例子吗?我在 CTE 中看到的只是 SELECT 语句。
  • 有趣 - SQL Server 绝对不允许在 CTE 中使用 DML。
  • @DStanley 请参阅stackoverflow.com/a/26419153/7870359 last secret 以获得一个很好的例子。

标签: sql postgresql common-table-expression


【解决方案1】:
  • 语法 CTE 的行为与任何其他表表达式 相同。

  • 语义上是不同的。 [在 Postgres 中] 它会总是被执行 一次,即使它被多次引用。

  • [在 Postgres 中] CTE 将充当优化障碍;查询词不能在 CTE 和主查询之间(移入或移出)移动。


第二点和第三点可能会产生严重影响。由于障碍&exactly once,CTE 扫描很难利用隐式顺序或 CTE inside 索引的存在。 CTE 扫描的行为或多或少类似于对无序表或物化视图的顺序扫描。对于小型 CTE,这不会有问题,因为可以使用散列连接。大型 CTE 需要物化 + 排序才能将 CTE 加入主查询。

【讨论】:

    【解决方案2】:

    在 postgres 中,cte 不应被视为内联视图,尽管将其视为存在于语句范围内的物化视图是有用的。如果 CTE 在查询的另一部分中被引用,或者如果它更改数据(插入/更新/删除),则将实现 CTE。

    因此,由于您的示例更改了数据,因此会评估 CTE,而您引用的链接具有不会更改数据的 CTE。

    而在其他数据库中,来自外部查询的谓词将由优化器下推到 CTE,而在 postgresql 中,CTE 将完全实现。

    例如

    WITH cte AS (SELECT * FROM foo WHERE foo.bar = True)
    SELECT * FROM cte WHERE cte.id > 10 AND cte.id < 20
    

    比 postgresql 慢

    SELECT * FROM (SELECT * FROM foo WHERE bar = TRUE) cte
    WHERE cte.id > 10 AND cte.id < 20
    

    这是一种在外部查询中具有可选或动态谓词的考虑因素。稍快的 CTE 版本将是

    WITH cte AS (SELECT * FROM foo WHERE foo.bar = True AND foo.id > 10 AND foo.id < 20)
    SELECT * FROM cte
    

    这是设计使然,您可以依靠此行为来创建优化障碍。

    在允许 SELECT 子句的任何地方都允许使用 CTE。因此,可以在 INSERT、UPDATE 或 DELETE 语句中使用 CTE。 我不确定这是否是 SQL 标准的一部分

    例如,在 9.5 版和 INSERT ... ON CONFLICT 语法的引入之前,我们可以使用 CTE 来执行 UPSERT。 Here's a SO thread that illustrates with an example

    还有第二种更有趣的 CTE 类型,即 RECURSIVE CTE,其中 CTE 由迭代部分和可处理迭代部分中生成的值的应用部分的联合组成。我不认为这种类型的查询可能内联

    【讨论】:

      猜你喜欢
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多