Jac*_*las 10 postgresql optimization cte postgresql-9.3
我使用以下递归 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
*/
Run Code Online (Sandbox Code Playgroud)
请注意上述计划中的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)
*/
Run Code Online (Sandbox Code Playgroud)