2017-06-17 20 views
3

[9.6.1的PostgreSQL在x86_64-PC-Linux的GNU,与gcc编译(Debian的6.2.0-10)6.2.0 20161027,64比特]不一致统计

我有与时间戳的表范围:

create table testing.test as 
select tsrange(d, null) ts from 
generate_series(timestamp '2000-01-01', timestamp '2018-01-01', interval '1 minute') s(d); 

我需要运行下面的查询:

select * 
from testing.test 
where lower(ts)> '2017-06-17 20:00:00'::timestamp and upper_inf(ts) 

解释分析结果的表没有索引:

Seq Scan on test (cost=0.00..72482.26 rows=1052013 width=14) (actual time=2165.477..2239.781 rows=283920 loops=1) 
    Filter: (upper_inf(ts) AND (lower(ts) > '2017-06-17 20:00:00'::timestamp without time zone)) 
    Rows Removed by Filter: 9184081 
Planning time: 0.046 ms 
Execution time: 2250.221 ms 

接下来我要添加以下部分索引:

create index lower_rt_inf ON testing.test using btree(lower(ts)) where upper_inf(ts);  
analyze testing.test; 

解释与部分索引表分析结果:

Index Scan using lower_rt_inf on test (cost=0.04..10939.03 rows=1051995 width=14) (actual time=0.037..52.083 rows=283920 loops=1) 
    Index Cond: (lower(ts) > '2017-06-17 20:00:00'::timestamp without time zone) 
Planning time: 0.156 ms 
Execution time: 62.900 ms                           

和:

SELECT null_frac, n_distinct, correlation FROM pg_catalog.pg_stats WHERE tablename = 'lower_rt_inf' 

null_frac |n_distinct |correlation | 
----------|-----------|------------| 
0   |-1   |1   | 

然后我创建了一个类似于前一个的索引,但没有部分条件:

create index lower_rt_full ON testing.test using btree(lower(ts)); 
analyze testing.test; 

而现在使用相同的指标,但成本/行是不同的:

Index Scan using lower_rt_inf on test (cost=0.04..1053.87 rows=101256 width=14) (actual time=0.029..58.613 rows=283920 loops=1) 
    Index Cond: (lower(ts) > '2017-06-17 20:00:00'::timestamp without time zone) 
Planning time: 0.280 ms 
Execution time: 71.794 ms                          

而且多一点:

select * from testing.test where lower(ts)> '2017-06-17 20:00:00'::timestamp; 

Index Scan using lower_rt_full on test (cost=0.04..3159.52 rows=303767 width=14) (actual time=0.036..64.208 rows=283920 loops=1) 
    Index Cond: (lower(ts) > '2017-06-17 20:00:00'::timestamp without time zone) 
Planning time: 0.099 ms 
Execution time: 78.759 ms 

我如何才能有效使用部分索引表情?

回答

0

这里发生的是,索引lower_rt_full的统计信息用于估计行计数,但lower_rt_inf是部分索引,不是。

由于函数是PostgreSQL的黑盒子,因此不知道lower(ts)的分布情况,并使用错误的估计值。

在创建了lower_rt_full并对表进行分析后,PostgreSQL对此分布有了一个很好的想法,并且可以估计得更好。即使索引不用于执行查询,它也用于查询计划。

由于upper_inf也是一个函数(黑匣子),如果您有索引ON test (upper_inf(ts), lower(ts)),您会得到更好的估计。

为什么部分指标不被认为估计结果的行数,看到examine_variablebackend/utils/adt/selfuncs.c此评论,它试图找到一个表达的统计数据说明:

* Has it got stats? We only consider stats for 
* non-partial indexes, since partial indexes probably 
* don't reflect whole-relation statistics; the above 
* check for uniqueness is the only info we take from 
* a partial index. 
0

感谢您的回答。 在索引中使用函数的问题(lower(rt))? 或者该功能用于部分索引的情况。

因为,如果我添加一个单独的领域 “最新”:

alter table testing.test add column latest boolean; 
update testing.test set latest = upper_inf(ts); 
create index lower_latest_rt ON testing.test using btree(lower(ts)) where latest = true; 
alter index testing.lower_latest_rt alter column lower set statistics 1000; 
analyze testing.test; 

和执行follwing查询:

select * 
from testing.test 
where lower(ts)> '2017-06-17 20:00:00'::timestamp and latest = true 

我有结果:

Index Scan using lower_latest_rt on test (cost=0.04..11406.44 rows=285833 width=23) (actual time=0.027..178.054 rows=283920 loops=1) 
Index Cond: (lower(ts) > '2017-06-17 20:00:00'::timestamp without time zone) 
Planning time: 1.788 ms 
Execution time: 188.481 ms