Reputation: 551
Using postgres9.6. All statistics up to date, everything vacuumed and repacked.
We all know about 10% of the internet is devoted to "why isnt postgres using my index"....this is one of those
I have a table session
, with index on primary key id
. When I do the following update its slow (5+ minutes)
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
Explain seen here: https://explain.depesz.com/s/FtI4 The culprit is the seq_scan at the bottom.
However when instead of a CTE I dump the result into a temp table and then join on that for the update its blazing fast, explain here: 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;
Can someone explain why the cte is tripping up the planner so badly? Why in the temp table case the correct index is chosen?
Upvotes: 3
Views: 830
Reputation: 246688
You didn't say it in so many words, but it looks like you ran ANALYZE
on the temporary table, because the estimate of 1 row is spot an.
That makes the difference.
PostgreSQL runs the same query, regardless if it is a CTE or creates a temporary table, and that query is fast, as you correctly observe.
Unfortunately PostgreSQL's estimate of the number of rows found by that subquery is horribly wrong — I'll analyze (hint, hint!) the cause later on.
This wrong estimate is corrected by the creation of the temporary table and particularly the ANALYZE
, so you end up with a good execution plan.
But let's take a step back.
Why is the misestimate so bad? The reason are the misestimates of the scans on alias_staging_zml
and session_fbc669c0_3cce_4322_83a6_8b80da7ed545
. So you should ANALYZE
these tables, and that should change everything else.
If ANALYZE
doesn't improve things, you might have to increase the statistics target for the column, e.g.
ALTER TABLE session_fbc669c0_3cce_4322_83a6_8b80da7ed545
ALTER person_id SET STATISTICS 1000;
Upvotes: 3