最小限の例として次の再帰CTEを使用していますが、一般的に、オプティマイザは再帰CTEにデフォルトの「推測」カーディナリティを使用する必要があります。
with recursive w(n) as ( select 1 union all select n+1 from w where n<5 ) select * from w;
/*
n
---
1
2
3
4
5
*/
explain analyze
with recursive w(n) as ( select 1 union all select n+1 from w where n<5 ) select * from w;
/*
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
CTE Scan on w (cost=2.95..3.57 rows=31 width=4) (actual time=0.005..0.020 rows=5 loops=1)
CTE w
-> Recursive Union (cost=0.00..2.95 rows=31 width=4) (actual time=0.003..0.017 rows=5 loops=1)
-> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1)
-> WorkTable Scan on w w_1 (cost=0.00..0.23 rows=3 width=4) (actual time=0.002..0.002 rows=1 loops=5)
Filter: (n < 5)
Rows Removed by Filter: 0
*/
rows=31
見積もりとrows=5
上記の計画の実際のカーディナリティ。推定として100が使用されているように見える場合もありますが、推測の背後にある正確なロジックはわかりません。
私の現実の問題では、カーディナリティの見積もりが悪いため、高速な「ネストされたループ」プランを選択できません。再帰CTEがオプティマイザのカーディナリティを「ヒント」にしてこれを回避するにはどうすればよいですか?
私はこのような問題を回避してきましたが、あまり賢くない方法があることを願っています:
explain analyze
with recursive w(n) as ( select 1 union all select n+1 from w where n<5 )
select * from w limit (select count(*) from w);
/*
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
Limit (cost=3.66..3.72 rows=3 width=4) (actual time=0.032..0.034 rows=5 loops=1)
CTE w
-> Recursive Union (cost=0.00..2.95 rows=31 width=4) (actual time=0.003..0.019 rows=5 loops=1)
-> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.000..0.000 rows=1 loops=1)
-> WorkTable Scan on w w_1 (cost=0.00..0.23 rows=3 width=4) (actual time=0.002..0.002 rows=1 loops=5)
Filter: (n < 5)
Rows Removed by Filter: 0
InitPlan 2 (returns $2)
-> Aggregate (cost=0.70..0.71 rows=1 width=0) (actual time=0.029..0.030 rows=1 loops=1)
-> CTE Scan on w w_2 (cost=0.00..0.62 rows=31 width=0) (actual time=0.005..0.025 rows=5 loops=1)
-> CTE Scan on w (cost=0.00..0.62 rows=31 width=4) (actual time=0.000..0.002 rows=5 loops=1)
*/