我有一个25mln行" zemla"表,带有索引
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会用这么多开销进行另一个位图堆扫描?
编辑:什么是" bitmap heap scan"在查询计划中?是另一个问题,因为它回答了为什么与某些查询或操作员进行位图堆扫描。我的疑问既没有,也没有运营商
如果我没记错的话,位图堆扫描是从磁盘中获取数据的算法。它分析了发动机必须获取并对其进行排序以使其最小的硬驱动头运动的所有磁盘页面。
这需要时间,因为您的桌子必须非常大,并且可能在磁盘上高度分散。
对于您的第二个查询count(*)
,PostgreSQL仍需要读取结果行以验证它们是否存在;在这种情况下,其他数据库系统可能只需要引用索引。检查此页面以获取更多信息:
https://wiki.postgresql.org/wiki/index-only_scans
尝试桌子上的VACCUM FULL
,看看它是否加快了速度。