PG的多版本并发控制(二)
二、 PG数据库DML操作的相关概念
xmin、xmax、cmin、cmax是每个数据行tuple上的隐藏字段,主要用于区别不同事务以及相同事务内tuple的行版本。在了解这四个参数概念前,我们首先需要知道,每个事务都会分为一个事务ID,在同一个事务中执行的每条命令都会分配一个命令ID。
xmin : 当一个事务插入一条新的数据行时,将该数据行的xmin标识为当前事务的事务ID
xmax :新插入的数据行的xmax默认为0,当一个事务删除一条数据行时,将该数据行的xmax标识为当前事务的事务ID,相当于做了一个删除标记。
cmin/cmax : 在同一事务内,当该命令操作导致会插入/删除操作时,使用cmin、cmax进行计数
2.1 t_xmin、t_xmax行为方式
当新插入一行数据时,将xmin设置为当前事务ID、xmax设置为0;
当删除某一行记录时,将该记录行的xmax设置为当前的事务ID;
当修改某一行时,实际上是将旧数据行的xmax设置为当前事务ID,然后新插入变更后的数据行,并将该数据行的xmin设置为当前事务ID
INSERT
DELETE
UPDATE
2.2 cmin、cmax的行为方式(t_cid)
在每个事务在事务开始的时候,命令标识计数器被初置为0,每当执行更新命令(如I\U\D\select ... for update)时,SQL执行后的命令标识计数标计数值+1。PG每个事务中的命令标识计数最大为2^23-1个,若超过该数据后就会发生回卷,计数器开始从0开始计数。
2.3 commit log(CLOG)
commit log也被称为clog,它是pg数据库共享内存中的一块区域,主要用来保留各个事务的事务状态,主要包含以下四种状态: IN_PROGRESS、COMMITTED、ABORTED、SUB_COMMITTED。clog由一个或多个8K的数据页组成,逻辑上以数组的形式记录每个t_xid的事务状态。随着事务的不断增长,clog也会不断增大,此时pg数据库的vacuum process就会负责对clog中无效数据进行清理。
IN_PROGRESS :表示事务正在进行中
COMMITTED :表示事务已提交
ABORTED :表示事务已回滚
SUB_COMMITTED :表示子事务已提交
当数据库关闭或者检查点运行时,pg会将clog的数据全部记录在 $PGDATA 中的 pg_xact 目录下的0000、0001文件中进行落盘;当数据库启动时,加载 pg_xact 文件中对事务状态的记录来初始化clog。
在PG数据库中,若一个事务失败,在数据文件中这个事务产生的数据并不会在事务回滚时被清理掉。这样做主要是出于效率考虑,避免事务在回滚或者提交时再次标记数据而额外的多产生一次IO消耗,当事务提交/回滚时会通过共享内存中的clog将所有事务的事务状态进行记录,只需要通过tuple上的tmin、tmax就可以知道对应的事务是成功提交还是回滚掉了,验证记录行的有效性。
2.4 事务快照
事务快照以“xmin:xmax:xip_list”的形式进行存储,可通过内置函数txid_current_snapshot()进行调用查看当前事务下的事务快照信息。通过事务快照我们可以清楚的知道当前事务下一些活跃与非活跃状态的事务信息,并通过tuple的xmin、xmax、clog的事务状态进行一定的版本控制。xmin : 事务当前状态下最早的活跃事务,此事务ID之前的所有事务都为非活跃状态
xmax : 事务当前状态下下最早的活跃事务,该事务ID之后的所有事务都为活跃状态
xip_list : 当前事务链下xmin与xmax之前所有活跃的事务ID号列表
需要我们注意的就是,事务快照在同一个事务中并不是一成不变的,若在事务未完成之前并发其他事务提交,在不同的时间点该事务下的事务快照信息是不一样的。