【发布时间】:2015-06-10 15:09:24
【问题描述】:
我有一个包含 16 列的表,其中有一个主键和一个用于存储值的列。 我想选择一定范围内的所有值。 值列 (easyid) 已被索引。
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)的输出 -
您的表中可能没有足够的数据让规划者来处理索引。要查看是否会使用该索引,请在控制台中输入
set enable_seqscan = off;并重试。这将使 PostgreSql 尽可能避免顺序扫描。 -
@a_horse_with_no_name 解释添加
-
(auto)vacuum 正在运行?顺便说一句,您的 Postgres 版本是什么?而real表定义,我想rowsize大于8字节)
-
你到底为什么要关闭 autovacuum?
标签: sql postgresql