基于 CSN的 MVCC机制
openGauss采用行级MVCC机制,历史版本集中存储,垃圾清理代价低。每个事务有一个单独的事务状态存储区域,记录了该事务的状态信息和 CSN。CSN 在openGauss内部使用一个全局自增的长整数作为逻辑的时间戳,模拟数据库内部的时序。
例如,如图12所示,图中每个非只读事务在运行过程中会取得一个 xid(事务号),在事务提交时会推进 CSN,同时会将当前 CSN 与事务的xid映射关系保存起来。
因此当一个事务拿到的快照为 CSN=3时,事务 TX2、TX4、TX6、TX7、TX8的CSN 分别为4、6、5、7、8,对于该事务的快照而言,这几个事务的修改都不可见。
MVCC解决的是读写并发冲突问题。更新数据的时候,原地更新,把老版本放到历史版本区页面里,同时维护新版本元组到老元组的指针。读元组的时候,根据快照Snapshot.CSN 来判断应该读到哪个版本。
数据库在执行SQL的时候,首先会获取一个快照时间戳Snapshot,当扫描数据页面的时候,根据Snapshot.CSN 和事务状态来判断哪个元组版本可见或者都不可见。主要分以下3种场景:
元组的事务状态区中是回滚状态或者运行中状态,不可见。
元组的事务状态区中是提交状态,如果 Snapshot.CSN 比事务区里的CSN小,当前元组不可见,读取前一个版本继续比较 CSN。反之可见。
元组的事务状态区中是待提交状态,需要等待提交。CSN 本身与xid也会留存一个映射关系,以便将事务本身及其对应的可见性进行关联,这个映射关系会留存在 CSN Log中,如图13所示。

简单地总结如下:
如果当前事务ID小于一行的xmin,那么就需要检索xmin对应的 Clog,读取此事务状态,以此来判断此行数据是否对当前事务可见。
如果当前事务ID 大于一行中的 xmax,那么说明此行数据的更新/删除发生于本事务开始之前,此行数据对本事务一定不可见(但不排除此行数据的新版本对本事务可见,因为新旧版本是单独进行判断的)。
如果xid落在了xmin、xmax中间,就需要依据 CSN 来判断本事务的快照下对应数据是否应该被看到,需要检索 CSN Log来进行对比判断。
原文链接:https://blog.csdn.net/GaussDB/article/details/116012521




