[英]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_zml
和session_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.