繁体   English   中英

在CTE上使用join进行更新不使用索引,但是使用临时表

[英]update with join on CTE doesn't use index, but with temp table it does

使用postgres9.6。 所有统计数据都是最新的,所有内容都用吸尘器重新包装。

我们都知道大约10%的互联网致力于“为什么不使用我的索引postgre”....这是其中之一

我有一个表session ,主键id上有索引。 当我做以下更新时它的速度很慢(5分钟以上)

WITH session_cte as (

  --big complex cte, however the cte itself is FAST

)
update session S set S.foo = Z.foo
from session_cte as Z
where Z.id = S.id

解释如下: https ://explain.depesz.com/s/FtI4罪魁祸首是底部的seq_scan。

然而,当我将结果转储到临时表中而不是CTE时,我将结果转储到临时表中,然后加入更新,它的速度非常快,请在此处解释: https//explain.depesz.com/s/W3c6

create temp table session_cte_temp AS ( 
   --same complicated SQL as in the CTE
 );
 update session S set S.foo = Z.foo
 from session_cte as Z
 where Z.id = S.id;

有人可以解释为什么cte如此糟糕地绊倒计划者? 为什么在临时表中选择正确的索引?

你没有用这么多的话来说,但看起来你在临时表上运行了ANALYZE ,因为估计1行是现货。

这有所不同。

PostgreSQL运行相同的查询,无论它是CTE还是创建临时表,并且该查询很快,正如您正确观察到的那样。

不幸的是,PostgreSQL对该子查询找到的行数的估计是非常错误的 - 我将在后面分析(提示,暗示!)原因。

通过创建临时表特别是ANALYZE来纠正这个错误的估计,因此您最终得到了一个好的执行计划。

但让我们退后一步。

为什么misestimate如此糟糕? 原因是alias_staging_zmlsession_fbc669c0_3cce_4322_83a6_8b80da7ed545上的扫描错误估计。 所以你应该ANALYZE这些表,这应该改变其他一切。

如果ANALYZE没有改进,你可能必须增加列的统计目标,例如

ALTER TABLE session_fbc669c0_3cce_4322_83a6_8b80da7ed545
   ALTER person_id SET STATISTICS 1000;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM