【发布时间】:2017-05-17 07:38:36
【问题描述】:
我有点困惑,为什么使用 with 子句的简单 SQL 查询比将它们放在子查询中花费的时间要长得多。我的 IDE 上超过 100 万条记录的实例使用 with 子句运行 > 30 分钟,使用子查询仅运行
下面只举一个简单的例子:
with table1 as (select tb1.a, tb1.b, tb2.c, tb3.d
from tablea
where a > 0 and b = 2016)
table2 as (select a, b, c, d, e, f
from table1 tb1
left join table2 tb2 on tb1.a=tb2.a
left join table3 tb3 on tb1.b=tb2.b)
select * from table2
与将它们作为子查询相比:
select * from (select a, b, c, d, e, f
from (select tb1.a, tb1.b, tb2.c, tb3.d
from tablea
where a > 0 and b = 2016) tb1
left join table2 tb2 on tb1.a=tb2.a
left join table3 tb3 on tb1.b=tb2.b) table2
后者的查询完成速度比前者快得多。但是,前者在查询结构上更容易理解,所以如果可能的话,我更喜欢它。
不知道这个巨大的差异是由于我在解释时使用的IDE(DBeaver),还是基于SQL语句逻辑本身?
谢谢。
【问题讨论】:
-
请提供两者的执行计划
-
这被称为“postgresql 的优化围栏行为”。我确定它在 dba.stackexchange 上。
-
顺便说一句,如果有人做这项工作,这可能会在 v11 中消失。黑客名单上的This lengthy thread 或多或少达成共识,取消它并引入
MATERIALIZED关键字,允许您明确选择旧行为。 -
@LaurenzAlbe 我已经关注了邮件列表上的讨论。恕我直言,更好的命名是
NOT MATERIALIZED,因为标准 CTE 已经表现得好像物化了,尤其是在多次引用时。 -
并非所有 CTE 都可以内联。对于那些不能,行为将保持不变。除非使用
MATERIALIZED,否则新行为将尽可能内联。基本上,关键字的意思是“表现得像旧版本一样”,是一种查询提示。
标签: sql postgresql common-table-expression dbeaver