为什么 PostgreSQL 会为简单的查询做如此艰难的计划?

Why PostgreSQL does so hard plan for simple query?

我有 2500 万行 "Zemla" table 索引

CREATE INDEX zemla_level
  ON public."Zemla"
  USING btree
  (level);

现在我做简单的查询

select * from "Zemla" where level = 7

并获得非常困难的查询计划

Bitmap Heap Scan on "Zemla"  (cost=18316.26..636704.15 rows=978041 width=181) (actual time=216.681..758.663 rows=975247 loops=1)
  Recheck Cond: (level = 7)
  Heap Blocks: exact=54465
  ->  Bitmap Index Scan on zemla_level  (cost=0.00..18071.74 rows=978041 width=0) (actual time=198.041..198.041 rows=1949202 loops=1)
        Index Cond: (level = 7)

还有另一个简单的查询,我认为应该在索引存在时立即执行

select count(*) from "Zemla" where level = 7

Aggregate  (cost=639149.25..639149.26 rows=1 width=0) (actual time=1188.366..1188.366 rows=1 loops=1)
  ->  Bitmap Heap Scan on "Zemla"  (cost=18316.26..636704.15 rows=978041 width=0) (actual time=213.918..763.833 rows=975247 loops=1)
        Recheck Cond: (level = 7)
        Heap Blocks: exact=54465
        ->  Bitmap Index Scan on zemla_level  (cost=0.00..18071.74 rows=978041 width=0) (actual time=195.409..195.409 rows=1949202 loops=1)
              Index Cond: (level = 7)

我的问题是,为什么 PostgreSQL 在第一次索引扫描后执行另一个位图堆扫描,开销如此之大?

编辑:What is a "Bitmap heap scan" in a query plan? 是另一个问题,因为它回答了为什么某些使用 OR 运算符的查询具有位图堆扫描。我的查询既没有 OR 也没有 AND 运算符

如果我没记错的话,bitmap Heap Scan就是从磁盘中获取数据的算法。它分析引擎必须获取的所有磁盘页面并对其进行排序,以最大限度地减少硬盘磁头移动。

这需要时间,因为您的 table 必须非常大并且可能在磁盘上高度碎片化。


对于您的第二个查询 count(*),PostgreSQL 仍需要读取结果行以验证它们是否存在;其他数据库系统可能只需要在这种情况下引用索引。查看此页面以获取更多信息:

https://wiki.postgresql.org/wiki/Index-only_scans


在 table 上尝试 VACCUM FULL,看看它是否加快速度。