直接回答:PG 的 MVCC 用元组头的事务号(xmin/xmax)实现:INSERT 写入记录创建事务,UPDATE 不原地改而是写新版本并标记旧版本删除(xmax),DELETE 只标 xmax。每个事务按自己的快照(事务 ID 加活跃列表)判断哪些版本可见——读写互不阻塞。副作用是死元组(dead tuple)持续堆积,VACUUM 的职责就是回收这些空间并维护可见性映射;长期不清理就是表膨胀,扫描变慢、磁盘失控。

展开解析:治理要点:autovacuum 默认开着但参数保守,高频更新的大表要按表调优(autovacuum_vacuum_scale_factor 从 0.2 降到 0.02 类);长事务是膨胀的头号元凶——快照存在期间所有死元组都不能回收,监控 pg_stat_activity 里 idle in transaction 和超长查询。膨胀已发生时:VACUUM FULL/pg_repack 重建表(后者在线),日常靠 autovacuum 维持水位。关联问题:HOT update(索引列不变的更新可同页完成)显著减轻膨胀,所以表的 fillfactor 预留(如 80)对更新密集表有效;xmin/xmax 回卷(20 亿事务)靠 VACUUM FREEZE 防御,监控 oldest xmin。理解这套机制后,"update 频繁导致索引也膨胀"(新版本要新索引项)就顺理成章了。

追问方向:快照里记录哪些信息?为什么长事务会阻止全局回收?HOT 更新的前提条件?

(约 470 字)