I've run into issues before with systems where the result of a CTE is so large that it is actually advantageous to instead place it into a temp table to avoid re-fetching the data at each invocation. Sometimes that can be better than a CTE for this use case - YMMV.
select a.foo, b.bar
from a, b
where a.b_id = b.id
and a.something ='blah'
would be reliably 5-10% faster than select a.foo, b.bar
from a
join b on a.b_id = b.id
where a.something ='blah'
even if everything was indexed etc.Conversely, projecting off unnecessary columns used to result in a big speedup. ie
select a1.foo, b.bar
from
(select foo, b_id from a where something='blah') a1
join b on a1.b_id = b.id
used to be significantly faster than either of those queries on wide tables.edit: few typos and additional example added
Any chance you either had a lot more tables joined together, or you were seeing caching effects?
> Conversely, projecting off unnecessary columns used to result in a big speedup.
That also just gets inlined, unless you have more than from_collapse_limit items in the from list. And we push down the list of columns we actually need, so there's nothing this would improve anyway.
So instead of
...you can have ...obviously a trivial example but you get the idea. When I tested this on postgres (some time ago) this was very significantly faster for my use case.It also helps in use cases where you want to allow user-defined filtering and ordering logic controlled by a gui. You can put your basic query as the CTE and then have all the user-controlled bits and pieces in the final select and they don't get mixed up together.