Loading

InnoDB MVCC——隐藏字段、Undolog、ReadView

和MVCC相关的三个东西

  • 隐藏字段:InnoDB表中的每个行前都有的三个隐藏字段,用于实现MVCC机制
  • undolog:用于记录数据的历史版本,每一个数据的历史版本在undolog中构成一个历史版本链
  • readview*:每个事务都有一个,用于确定它能读到链中的哪些历史版本

隐藏字段

通过这一小节,你将知道InnoDB为了实现MVCC机制,在数据行上做了什么,它添加了三个隐藏字段

  • DB_TRX_ID:最后对该行进行插入或修改的事务ID
  • DB_ROLL_PTR:回滚指针,指向该数据的上一个版本,用于维护历史版本链
  • DB_ROW_ID:隐藏主键,只有当表没设置主键时才有,它和MVCC也没啥关系

undolog

通过这一小节,你将知道undolog是如何保存一行数据的历史版本的,以及DB_ROLL_PTR如何构建版本链,为了简单,我们省略DB_ROW_ID

假设现在有这样一个表,它只有一个列A

  1. 事务1刚刚插入了一行,A=1

    img

  2. 事务2修改这一行,A=2

    1. 把该行数据拷贝到undolog
    2. 执行这个修改,设置DB_TRX_IDDB_ROLL_PTR

    img

  3. 事务3再修改这一行,A=6

    img

ReadView

通过这一小节,你将知道当一个事务进行快照读时,如何确定自己应该读取历史版本链中的哪个数据。

ReadView快照能够在事务的查询中帮助解决这个问题,快照中包含以下关键内容:

  1. m_ids:当前系统中活动(已经开始,尚未提交回滚)事务id列表,有序
  2. max_trx_id:下一个尚未分配的事务id
  3. min_trx_idm_ids列表中最小的一个id

然后,假如我们就拿可重复读的标准来考虑,并假设ReadView生成的时间就是当前查询事务开启的时间

  • 如果待查询数据的DB_TRX_ID < min_trx_id,因为该数据在ReadView快照生成时已经是提交过的了,直接使用就行
  • 如果待查询数据的DB_TRX_ID = 当前事务id,一个事务肯定能读到自己做的修改,直接使用就行
  • 如果待查询数据的DB_TRX_ID >= max_trx_id,那么该数据是ReadView生成时尚未提交过的,需要沿DB_ROLL_PTR访问undolog的历史版本链,找到该读的数据
  • 还有种可能是DB_TRX_ID属于[min_trx_id, max_trx_id)这个区间
    • 如果DB_TRX_ID在列表中,说明它在ReadView创建时还未提交,不能使用,需要访问历史版本链
    • 否则,它在ReadView创建时已经提交,直接访问该数据

如果给事务一个ReadView,让事务按上面的规则进行读取,那么事务就能读取到ReadView生成时已经提交的最新版本数据

众所周知,MVCC机制支持在Read CommittedRepeatable Read级别下工作,那么我们只需要控制生成ReadView的时机,就可以模拟出这两种隔离级别应有的读取行为

  • Read Committed级别时,每次遇到读取命令生成一个ReadView
  • Repeatable Read级别时,第一次遇到读取命令生成一个ReadView,并且该ReadView在整个事务中共享
posted @ 2022-09-26 18:19  yudoge  阅读(519)  评论(0编辑  收藏  举报