常见关系库MVCC浅析1

分类: 工作学习 |
Oracle的MVCC的实现
Oracle的MVCC也是基于回滚段来实现的,即历史版本并不作为业务数据文件的一部分,而是作为undo日志的一部分。
Oracle的数据行中基本没有存储事务信息,只存储了一个锁信息,每个数据行有个LB位,如果为0那么说明这行数据没有被锁定,否则LB存储的是这个行锁所对应的事务在ITL(Interest transaction list)中的slot编号。ITL位于数据块头部,它包含了这个数据块的在进行或已经完成的事务信息,一个进行中的事务必然占用一个slot,而一个完成的事务对应的slot可以被一个新事务覆盖,slot的数量是有限的。
ITL主要包含了:
1.
2.
3.
4.
5.
6.
PostgreSQL的MVCC实现
PostgreSQL的MVCC实现与Oracle基于回滚段的实现有一个非常大的差异,就是PG的历史数据是直接存储在业务数据文件中的,是业务数据文件的一部分。在PG的数据页中,每一数据行是一个Tuple,数据行中除了业务数据外在数据行header部分还会有一些系统字段:
xmin 创建该tuple时的事务ID(后续都称为CreationID),由INSERT或UPDATE操作时设置。
xmax 过期的事务ID(后续都称为ExpiredID),在删除该tuple时,记录此时的事务ID,或者更新这个tuple时在旧的tuple上记录更新操作时的事务ID;如果该值不为0,则说明该行数据进行过删除或更新或回滚。
cmin和cmax 标识在同一个事务中增删改元组时存储其序列值,从0开始,只有INSERT/UPDATE/DELETE操作会递增,用于同一个事务中实现版本可见性判断。
ctid 是用来记录当前元组或新元组的物理位置,有块号和快内偏移组成,可以用来查找元组的下一个版本在磁盘上的位置,如果这个元组被更新,则该字段指向更新后的新元组,所以一个元组是最新版本,当且仅当它的xmax为空或者它的ctid指向它自己。
t_infomask表明了xmin和xmax的状态(committed/invalid/aborted)等信息,而t_infomask2包含了该元组属性的个数(即表的列数)和其他一些标志信息。
而PG的MVCC和Innodb类似的地方是,它也需要继续活跃事务快照判定数据行的可见性。事务快照组成为:“xmin:xmax:xip_list”。事务快照的创建过程主要如下:
a、查看所有未提交并活跃的事务记录到数组xip_list;
b、选取数组中这些事务中最小的XID存储到该快照的xmin字段;
c、选取数组中这些事务中最大的XID加1后存储到该快照的xmin字段;
在MVCC过程中将基于快照来判断一个数据行当前事务是否可见。对于同一个业务数据的不同历史版本事务行,任何一个事务只会看到其中的一个版本。
MVCC的可见性判定的基本思路为通过判定一行记录的xmin和xmax对应的事务是否对当前事务快照是否已完成来判定一个数据行是否可见。如果xmin已经完成,但xmax还未完成,那么这个行就可见。
具体的判定逻辑为:
同一个行的多个历史版本都会被扫描。
Rule7为例,如果xmin已经提交,而xmax对应的事务还在运行中,而tmax是当前事务,那么这个行是这个事务内之前修改的行,不应该被看见。
Rule9为例,如果xmin已经提交,而xmax对应的事务状态是提交,tmax不是当前事务,并且这个事务还在当前事务快照中(即事务其实还在运行),那么说明这个行目前操作的终结事务id未提交,这个数据行还是可见的。
Rule10为例,如果xmin已经提交,而xmax对应的事务状态是提交,tmax不是当前事务,并且这个事务不在当前事务快照中(即事务真的已经提交了),那么这个行目前操作的终结事务id已经提交,即这个行已经被删除或废弃,这个数据行不可见。
上述rule中的status的判定可能会涉及到行t_infomask系统列和pg的pg_clog文件(记录事务的提交状态,是最准确的)。行t_infomask系统列的作用类似pg_clog的缓存,如果它的值是提交,那么就是准确的,如果不是提交,就需要再检查pg_clog文件。和Oracle的快速提交和延迟提交类似,pg的t_infomask系统列不是在事务提交的时候更新,而是后续被操作的时候更新,例如再查询到这个行的时候。
MySQL InnoDB的MVCC实现
MySQL
InnoDB的每个行都有2个系统隐藏字段DB_TRX_ID和DB_ROLL_PTR,前者是事务ID,后者是指向回滚段上一个历史版本的指针,一个历史版本可能还会通过DB_ROLL_PTR指向更早的版本。
InnoDB与Oracle不同,Oracle提交的时候会分配并存储Commit SCN,而InnoDB只存储了事务开始时分配的事务ID,所以InnoDB引入了活跃事务快照来做可见性判定。
基本的思想就是只能看见已经提交的最新版本,所有当前事务t启动或运行的时候还未开启或正在执行的事务t’对于t是不可见的。
活跃事务列表是维护在innodb全局trx_sys中的一个列表,即当前活跃事务的列表;而活跃事务快照是对活跃事务列表的一个瞬时拷贝,它是一个左闭右开的区间,up_limit_id:low_limit_id:ids。
Up_limit_id是活跃事务列表事务id的最小值,所有小于它的事务都是已提交可见的事务。Low_limit_id是全局要分配的下一个id,所有大于等于它的事务都是当前事务开始时还未启动的事务,都是不可见事务。而在Up_limit_id和low_limit_id之间的事务,如果在ids列表中的为不可见事务。
参考:
http://blog.itpub.net/26736162/viewspace-2141499/
https://blog.csdn.net/weixin_31966453/article/details/113309836
https://blog.csdn.net/yanzongshuai/article/details/104828772
http://mysql.taobao.org/monthly/2017/10/01/
https://blog.csdn.net/adson1987/article/details/90692153
gGwBnJFHHMsGWgg3higuYOLN
www.sysdb.cn
转载请注明转自高孝鑫的博客!