一、事务冻结
在PG中,事务ID(XID)为无符号的32bit数字,所以理论上事务ID最大值为2^32,约为42亿,消耗完成之后就会从头开始分配,0,1,2三个XID为内部XID,新的XID从3开始。
- 0 代表无效TransactionID
- 1 代表启动事务ID,只在初始化数据库时才会使用。比所有正常事务都旧
- 2 代表冻结事务ID。比所有正常事务都旧(9.4之前使用,之后就用标识位表示冻结了)
这种机制称为 ”事务回卷“,我们知道,PG判断行可见性是通过比较XID大小来进行的,一旦XID重新开始,新事物ID比所有的元组的xmin都小,这意味着新事物将看不到任何的记录,为此,在事务回卷时,9.4 之前,PG执行冻结操作,将之前所有的XID 修改为2,这样2 比所有新开始的事务ID都小,所以对新事物可见,但是这种冻结操作会对所有表的记录进行一次扫描修改,消耗大量IO和CPU,而且如果这个冻结操作不能很快完成(事实上它确实不能很快完成),必将会造成数据库长时间不能执行新事物,影响业务正常进行。
很多人习惯称这种场景为“冻结炸弹”,为了解决“冻结炸弹”问题,PG做了很多优化,包括通过标识位来表示冻结、惰性冻结等。通过一些参数,提前冻结,尽量避免事务XID被用尽。
两个问题
- 为什么XID为32位数字,而真正能事务ID最大只能到2^31?
因为事务ID为无符号32位数字,但是在事务ID比较时,需要将结果转换为有符号的32位数字,这样最高位表示符号,最大事务ID只能达到231。所以在PG中最新和最旧事物ID之间的差值不能超过231。
- 限制主流计算机已经是64位了,为什么不能将事务ID修改为64位数字
因为PG的XID是存储在元组首部的,每行记录都会消息一定存储空间。增加到64位会造成更高的元组首部消耗,所以目前PG一直没有将XID增加到64位。
二、冻结参数
冻结模式:
- **惰性模式:**冻结过程仅使用表对应的空闲空间映射文件中包含死元组的页面.
- **急切模式:**冻结过程会对表的整个页面进行扫描。无论该表页面中是否包含有死元组。并且在可能的情况下才会移除xact(clog)文件.
有四个控制冻结的主要参数。它们都表示事务年龄,并定义以下事件发生的时间
• 冻结开始 (vacuum_freeze_min_age).
• 主动执行冻结 (vacuum_freeze_table_age).
• 强制冻结 (autovacuum_freeze_max_age).
• 冻结优先级(vacuum_failsafe_age).
vacuum_freeze_min_age(默认5000w)参数定义xmin事务最新冻结年龄,惰性模式触发条件。它的值越低,开销越高。
vacuum_freeze_table_age(默认1.5亿)表做vacuum_freeze的触发年龄。急切模式触发条件
autovacuum_freeze_max_age(默认2亿) 强制做vacuum_freeze的最大表年龄(即使autovacuum关闭)。防止事务回卷,兜底参数,触发急切模式
三、冻结模式
创建测试数据和观察函数
CREATE TABLE test( id int,name char(300)) with (fillfactor=10,autovacuum_enabled&#