可见性映射(visibility map)是PostgreSQL中用于标记数据页是否全可见的位图结构,位于每个堆表对应的vm文件中,每页占一位,若所有元组对当前及未来事务可见则标记为1。它基于MVCC机制,通过事务ID(xmin、xmax)和事务快照判断行可见性,由VACUUM操作更新状态。其主要作用包括加速VACUUM跳过全可见页清理,以及支持index-only扫描时避免回查堆元组,提升查询性能。VM由系统自动维护,依赖定期执行VACUUM更新,长期不运行会导致性能下降;可通过VACUUM VERBOSE或pg_visibility_map()查看状态。临时表无VM,表删除时VM同步清除,页面修改后需重新标记。合理配置autovacuum可确保VM有效,优化整体性能。

PostgreSQL 的可见性管理是 MVCC(多版本并发控制)机制的核心部分,用于决定哪些数据版本对当前事务可见。理解可见性有助于优化查询性能、避免膨胀问题,并正确使用 VACUUM 等维护操作。在涉及 visibility map(可见性映射)时,PostgreSQL 使用它来提升扫描效率,尤其是在执行 VACUUM 和索引-only 扫描时。
可见性管理的基本原理
PostgreSQL 通过事务 ID(XID)和元组级别的系统字段(如 xmin、xmax)判断行的可见性:
- xmin:创建该行版本的事务 ID,若当前事务开始后该事务才提交,则此行不可见。
- xmax:删除或更新该行的事务 ID,若为空或未提交,则该行仍有效。
- 事务状态由 pg_clog(现为 pg_xact)记录,结合事务快照判断是否可见。
每个事务在开始时获取一个快照(snapshot),列出当时活跃的事务,基于此判断哪些数据版本可以看见。
什么是 visibility map(可见性映射)
Visibility map 是 PostgreSQL 中一种位图结构,用来标记数据页中所有元组是否对所有事务“已冻结”(frozen)或“全部可见”。
- 每个堆表(heap table)对应一个 vm 文件,命名规则为:relfilenode_vm,例如
12345_vm。 - 每一页在 vm 中占一位:若某页上所有元组都被所有当前及未来事务可见,则该位被置为 1。
- 这种页面称为“全可见页”(all-visible page)。
VM 不记录部分可见或不可见的情况,只表示“全可见”状态。
visibility map 的作用
VM 主要服务于两个关键功能:
- 加速 VACUUM 操作:VACUUM 可跳过 marked all-visible 的页面,因为这些页面无需清理死元组(除非被后续修改)。
- 支持 index-only scans:当查询仅访问索引时,若索引项指向的堆页在 VM 中标记为全可见,则数据库可直接返回数据,无需回查堆元组确认可见性,大幅提升性能。
如何管理和维护 visibility map
VM 是自动管理的,但依赖于 VACUUM 操作来更新其状态:
- 普通 VACUUM 在清理页面并确认所有元组都对所有事务可见后,会设置 VM 中对应的位。
- VACUUM FULL 或 CLUSTER 会重建表,通常重置 VM。
- 可以通过
VACUUM VERBOSE tablename;查看是否更新了 visibility map 中的页面数。 - 使用函数
pg_visibility_map('tablename')可查看表的 VM 统计信息,如全可见页数量。
注意:若长期不运行 VACUUM,VM 将无法更新,导致 index-only scan 效率下降,性能退化。
常见注意事项
- VM 文件不会永久保留;当关联的主文件被删除(如 DROP TABLE),VM 也会被清除。
- 临时表没有 visibility map。
- 在低更新频率的表中,VM 可能长时间保持有效,但一旦页面被修改,其 VM 位将被清除,需重新通过 VACUUM 设置。
- 使用
pg_freespacemap和pg_visibility扩展可进一步分析页面可见性与空间使用情况。
基本上就这些。visibility map 是 PostgreSQL 高效处理 MVCC 和索引优化的关键组件之一,合理配置 autovacuum 并定期维护表,才能充分发挥其优势。










