我有一个16列的表,其中有一个主键和一列存储值。 我想选择一定范围内的所有值。 值列(easyid)已编入索引。为什么这个查询不使用postgresql中的仅索引扫描
create table tb1 (
id Int primary key,
easyid Int,
.....
)
create index i_easyid on tb1 (easyid)
其他信息:postgresql 9.4,没有自动真空。 SQL是这样的。
select "easyid" from "tb1" where "easyid" between 12183318 and 82283318
理论上postgresql应该使用索引只扫描i_easyid
。 当范围"easyid" between A and B
很小时,它只能进行索引扫描。 当范围很大时,即B-A
是一个非常大的数字,postgresql使用位图索引扫描i_easyid
,然后位堆扫描tb1
。
我说错了索引扫描只有或不取决于范围的大小。 我试着用不同的参数进行同样的查询,有时候它只是索引扫描,有时候不是。
表格tb1
非常大,可达17G。 i_easyid
是600MB。
这里是对sql的解释。我不明白为什么4000行花费超过10秒。
sample_pg=# explain analyze select easyid from tb1 where "easyid" between 152183318 and 152283318;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on tb1 (cost=97.70..17227.71 rows=4416 width=4) (actual time=1.155..14346.311 rows=5004 loops=1)
Recheck Cond: ((easyid >= 152183318) AND (easyid <= 152283318))
Heap Blocks: exact=4995
-> Bitmap Index Scan on i_easyid (cost=0.00..96.60 rows=4416 width=0) (actual time=0.586..0.586 rows=5004 loops=1)
Index Cond: ((easyid >= 152183318) AND (easyid <= 152283318))
Planning time: 0.080 ms
Execution time: 14348.037 ms
(7 rows)
这里是索引的例子仅扫描:
sample_pg=# explain analyze verbose select easyid from tb1 where "easyid" between 32280318 and 32283318;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------
Index Only Scan using i_easyid on public.tb1 (cost=0.44..281.82 rows=69 width=4) (actual time=14.585..160.624 rows=33 loops=1)
Output: easyid
Index Cond: ((tb1.easyid >= 32280318) AND (tb1.easyid <= 32283318))
Heap Fetches: 33
Planning time: 0.085 ms
Execution time: 160.654 ms
(6 rows)
向我们展示了'explain(analyze,verbose)'的输出结果 – 2015-04-06 08:36:07
您的表中没有足够的数据可能让规划人员无法理解索引。要查看索引是否会被使用,请将'set enable_seqscan = off;'in输入到控制台并再次尝试。这将使PostgreSql尽可能地避免顺序扫描。 – jgm 2015-04-06 08:39:58
@a_horse_with_no_name解释加入 – worldterminator 2015-04-06 09:13:04