5.10 所需的维护进程

PostgreSQL的并发控制机制需要以下维护过程。

  1. 删除死元组及指向死元组的索引元组
  2. 移除提交日志(clog) 中非必需的部分
  3. 冻结旧的事务标识(txid)
  4. 更新FSM,VM,以及统计信息

5.3.2 节和 5.4.3 节分别解释了为什么需要第一个和第二个过程。第三个过程与事务标识回卷问题有关,本小节将概述事务标识回卷(txid wrap around) 问题。

在PostgreSQL中,清理过程(VACUUM)负责这些过程。清理过程(VACUUM)第六章 清理过程(VACUUM) 中描述。

5.10.1 冻结处理

接下来将介绍事务标识回卷(txid wrap around) 问题。

假设元组Tuple_1是由txid = 100事务创建的,即Tuple_1t_xmin = 100。服务器运行了很长时间,但Tuple_1一直未曾被修改。假设txid已经前进到了$ 2^{31}+100$,这时候正好执行了一条SELECT命令。此时,因为对当前事务而言txid = 100的事务属于过去的事务,因而Tuple_1对当前事务可见。然后再执行相同的SELECT命令,此时txid步进至$2^{31}+101$。但因对当前事务而言,txid = 100的事务是属于未来的,因此Tuple_1不再可见(图5.20)。这就是PostgreSQL中所谓的事务回卷问题。

图5.20 回卷问题图5.20 回卷问题

为了解决这个问题,PostgreSQL引入了一个冻结事务标识(Frozen txid) 的概念,并实现了一个名为FREEZE的过程。

在PostgreSQL中定义了一个冻结的txid,它是一个特殊的保留值txid = 2,在参与事务标识大小比较时,它总是比所有其他txid都旧。换句话说,冻结的txid始终处于非活跃状态 ,且其结果对其他事务始终可见。

清理过程(VACUUM 会调用冻结过程(FREEZE)。冻结过程将扫描所有表文件,如果元组的t_xmin比当前txid - vacuum_freeze_min_age(默认值为5000万)更老,则将该元组的t_xmin重写为冻结事务标识。在 第六章 清理过程(VACUUM) 中会有更详细的解释。

举个例子,如图5.21(a)所示,当前txid为5000万,此时通过VACUUM命令调用冻结过程。在这种情况下,Tuple_1Tuple_2t_xmin都被重写为2。

在版本9.4或更高版本中使用元组t_infomask字段中的XMIN_FROZEN标记位来标识冻结元组,而不是将元组的t_xmin重写为冻结的txid,如图5.21(b)所示。

图5.21 冻结过程图5.21 冻结过程

下一节:清理过程为指定的表,或数据库中的所有表执行以下任务。