我想知道是否有人可以解释为什么使用 CTE 而不是临时表会运行这么长时间...我基本上是从客户表中删除重复信息(为什么存在重复信息超出了本文的范围) ).
这是 Postgres 9.5。
CTE 版本是这样的:
with targets as
(
select
id,
row_number() over(partition by uuid order by created_date desc) as rn
from
customer
)
delete from
customer
where
id in
(
select
id
from
targets
where
rn > 1
);
我今天早上在运行了一个多小时后杀死了那个版本。
临时表版本是这样的:
create temp table
targets
as select
id,
row_number() over(partition by uuid order by created_date desc) as rn
from
customer;
delete from
customer
where
id in
(
select
id
from
targets
where
rn > 1
);
此版本在大约 7 秒内完成。
知道是什么原因造成的吗?
最佳答案
CTE 较慢,因为它必须按原样执行(通过 CTE 扫描)。
因此它是一个优化障碍;对于优化者来说,拆除 CTE 是不允许的,即使这会产生具有相同结果的更明智的计划。
不过,CTE 解决方案可以重构为连接子查询(类似于问题中的临时表)。现在,在 postgres 中,联合子查询通常比 EXISTS() 变体更快。
DELETE FROM customer del
USING ( SELECT id
, row_number() over(partition by uuid order by created_date desc)
as rn
FROM customer
) sub
WHERE sub.id = del.id
AND sub.rn > 1
;
另一种方法是使用TEMP VIEW
。这在语法上等同于临时表
的情况,但在语义上等同于联合子查询形式(它们产生完全相同的查询计划,至少在这种情况下)。这是因为 Postgres 的优化器拆解 View 并将其与主查询结合(上拉)。您可以将 view
视为 PG 中的一种宏。
CREATE TEMP VIEW targets
AS SELECT id
, row_number() over(partition by uuid ORDER BY created_date DESC) AS rn
FROM customer;
EXPLAIN
DELETE FROM customer
WHERE id IN ( SELECT id
FROM targets
WHERE rn > 1
);
[更新:关于 CTE 需要始终执行到完成,我错了,这只是数据修改 CTE 的情况]
关于sql - 使用 CTE 删除比在 Postgres 中使用临时表慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35751276/