1. PostgreSQL 32 位事务 ID(XID)为什么存在回卷风险(以 2^31 为模的环形比较,新旧会颠倒)?冻结(freeze,置为 FrozenTransactionId)如何让老版本“永久可见”从而安全回收 XID?
请解释 PostgreSQL 32 位事务 ID(XID)的回卷风险,以及冻结(freeze)如何解决该问题?
- XID 的 32 位与回卷
- 环形比较与新旧颠倒
- 冻结机制
PostgreSQL 的事务 ID(XID)是 32 位无符号整数,约 42 亿个。事务 ID 的比较不是按大小,而是按以 2^31 为模的环形范围("在过去 2^31 内"还是"在未来 2^31 内")。当长时间运行超过 2^31 个事务后,环形比较会让"很旧"的 XID 看起来"在未来",导致新旧颠倒、可见性判断错误。冻结机制:把老事务的 XID 置为 FrozenTransactionId(特殊值 2),它永远比任何真实 XID 旧,因此该行"永久可见"于所有事务,VACUUM 可安全回收该 XID 之后的空间。冻结让老版本不再依赖具体 XID,从而安全处理回卷。
回卷是 XID 32 位空间的根本风险。冻结把"可见性判定"从"与具体 XID 比较"变为"与 FrozenTransactionId 比较",使老版本永久可见,VACUUM 才能安全推进以便回收 XID。这是 MVCC 可见性实现的关键。