为什么这个查询在PostgreSQL中不使用仅索引扫描?

时间:2015-08-19 07:34:39

标签: postgresql

我有一个包含28列和7M记录的表,没有主键。

CREATE TABLE records (
  direction smallint,
  exporters_id integer,
  time_stamp integer
  ...
)

我在此表和真空表上创建索引(autovacuum打开)

CREATE INDEX exporter_dir_time_only_index ON sacopre_records
USING btree (exporters_id, direction, time_stamp);

我希望执行此查询

SELECT count(exporters_id) FROM records WHERE exporters_id = 50

该表有6982224条记录,其中exporters_id = 50.我希望此查询使用仅索引扫描来获取结果,但它使用顺序扫描。 这是“EXPLAIN ANALYZE”输出:

Aggregate  (cost=204562.25..204562.26 rows=1 width=4) (actual time=1521.862..1521.862 rows=1 loops=1)
->  Seq Scan on sacopre_records (cost=0.00..187106.88 rows=6982149 width=4) (actual time=0.885..1216.211 rows=6982224 loops=1)
    Filter: (exporters_id = 50)
    Rows Removed by Filter: 2663
Total runtime: 1521.886 ms

但是当我将exporters_id更改为另一个id时,查询使用仅索引扫描

Aggregate  (cost=46.05..46.06 rows=1 width=4) (actual time=0.321..0.321 rows=1 loops=1)
->  Index Only Scan using exporter_dir_time_only_index on sacopre_records  (cost=0.43..42.85 rows=1281 width=4) (actual time=0.313..0.315 rows=4 loops=1)
    Index Cond: (exporters_id = 47)
    Heap Fetches: 0
Total runtime: 0.358 ms

问题出在哪里?

1 个答案:

答案 0 :(得分:4)

解释告诉你原因。仔细观察。

Aggregate  (cost=204562.25..204562.26 rows=1 width=4) (actual time=1521.862..1521.862 rows=1 loops=1)
->  Seq Scan on sacopre_records (cost=0.00..187106.88 rows=6982149 width=4) (actual time=0.885..1216.211 rows=6982224 loops=1)
    Filter: (exporters_id = 50)
    Rows Removed by Filter: 2663
Total runtime: 1521.886 ms

您的过滤器只删除了表中6982149行总数中的2663行,因此执行顺序扫描应该比使用索引更快,因为磁盘头应该通过6982149 - 2663 = 6979486记录。磁头开始按顺序读取整个表,并且正在移除与您的条件不匹配的小部分(0.000004%)。在索引扫描的情况下,它应该从索引文件跳转并返回到数据文件6979486次,这肯定应该比你现在获得的这些1.5秒慢!