Skip to content

MVCC

提示

  • MVCC(多版本并发控制)指的就是在使用READ COMMITTD、REPEATABLE READ这两种隔离级别的事务在执行普通的SELECT操作时访问记录的版本链的过程。使不同的事务读写、写读并发执行,提升系统性能。
  • 事务利用MVCC进行的读取操作称之为一致性读。所有普通的SELECT语句(plain SELECT)在READ COMMITTEDREPEATABLE READ隔离级别下都算是一致性读

版本链

Innodb的行格式中包含两个隐藏列,分别是trx_idroll_pointer,如果没有主键或唯一索引也会创建隐藏列row_id

  • trx_id

每次一个事务对某条聚簇索引记录进行改动时,都会把该事务的事务id赋值给trx_id隐藏列。

只有在事务对表中的记录做改动时(增删改)才会为这个事务分配一个唯一的事务id。整个系统中分配的事务id值是一个递增的数字。先被分配id的事务得到的是较小的事务id,后被分配id的事务得到的是较大的事务id

  • roll_pointer

每次对某条聚簇索引记录进行改动时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。

undo日志被存放到了类型为FIL_PAGE_UNDO_LOG的页面中。

对记录每次更新后,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被roll_pointer属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。另外,每个版本中还包含生成该版本时对应的事务id

ReadView

概念

  • m_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。

  • min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也是m_ids中的最小值。

  • max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。

    注意max_trx_id并不是m_ids中的最大值,事务id是递增分配的。比方说现在有id为1,2,3这三个事务,之后id为3的事务提交了。那么一个新的读事务在生成ReadView时,m_ids就包括1和2,min_trx_id的值就是1,max_trx_id的值就是4。

  • creator_trx_id:表示生成该ReadView的事务的事务id

    只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会为事务分配事务id,否则在一个只读事务中的事务id值都默认为0。

规则

规则结果
trx_id = creator_trx_id着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
trx_id < min_trx_id当前事务在生成ReadView之前已提交(即不活跃),所以可以访问
trx_id >= max_trx_id当前事务在生成ReadView后才开启,所以不能访问
trx_id >= min_trx_id & trx_id < max_trx_id如果当前事务id在m_ids中,说明该事务仍活跃,则不能被访问,不在m_ids中则可以访问

依次和版本链中(包含页面中的那条数据)的数据依次进行比对,找到符合的数据就返回并退出比对。

生成时间

  • READ COMMITTED(每次SELECT前都生成一个ReadView

  • REPEATABLE READ(在第一次SELECT的时候生成一个ReadView