`
后来我们都老了
  • 浏览: 33768 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

深入了解MVCC

阅读更多

背景

MySQL的InnoDB引擎实现了多版本控制MVCC,其对RR和RC隔离级别提供了支持,RR和RC可以在快照读取数据,那InnoDB是如何支持快照读的呢?

MVCC 是如何操作的

童话里是这么说的

Select

InnoDB只查找版本小于或等于当前事务版本的数据行。确保事务读取到的行,要么是事务开始前就存在的,要么是事务自身插入或者修改的。
行的删除版本要么未定义,要么大于当前事务的版本。确保事务读取到的行,在事务开始之前未被删除。 

Insert

InnoDB为新插入的每一行保存当前系统版本号作为行版本号

Delete 

InnoDB为删除的每一行保存当前系统版本号作为行删除标识

Update

InnoDB会插入一行新记录保存当前系统版本号作为行版本号,同时保存当前系统的版本号到原来的行作为行删除标识

 

思考:如果每创建一个事务,都保存当前时刻一份全量的快照的话,不考虑数据库能不能抗的住,上面这些操作有何意义?

MVCC的数据结构

MVCC两个基本的数据结构

行记录

Innodb引擎会为每一行添加3个字段实现的,DATA_TRX_ID、DATA_ROLL_PTR与DELETED_BIT:

DATA _TRX_ID表示产生当前记录项的事务ID(每开启一个新的事务,其对应的事务id会自动递增);
DATA_ROLL_PTR一个指向此条记录项的undo信息的指针,undo信息是指此条记录被修改前的信息;
DELETED_BIT位,用于标识该记录是否被删除。

 

read view

RR读:每个事务在开始都会根据当前系统的活跃事务链表创建一个read_view,read_view是用来检索行的可见性的。 
RC读:事务中,每个语句都会创建read_view。
假设当前的活跃事务链表如下所示:current-trx —> trx7 —> trx5 —> trx3 —> trx1;

 

Read View中的的变量则按如下方式初始化:

read_view->creator_trx_id = current-trx;                       当前的事务id
read_view->up_limit_id = trx1;                                      当前活跃事务的最小id
read_view->low_limit_id = trx7;                                     当前活跃事务的最大id
read_view->trx_ids = [trx1, trx3, trx5, trx7];                   当前活跃的事务的id列表
read_view->m_trx_ids = 4;                                            当前活跃的事务id列表长度

 

 以上是read view中变量组成,下面来分析一下快照的形成过程
low_limit_id,即当时活跃事务的最大id,如果读到row的data_trx_id>=low_limit_id,说明这些数据在当前事务开始时都还没有提交,如注释中的描述,这些数据都不可见。

up_limit_id,即当时活跃事务列表的最小事务id,如果row的data_trx_id<up_limit_id,说明这些数据在当前事务开始时都已经提交,如注释中的描述,这些数据均可见。

data_trx_id在up_limit_id和low_limit_id之间的row,如果这个data_trx_id在trx_ids的集合中,就说明开启当前的事务的时候,这个data_trx_id还处于活跃状态,即还未提交,那么这个row是不可见的;如果这个data_trx_id不在trx_ids的集合中,就说明开启当前的事务的时候,这个data_trx_id已经提交,那么这个row是可见的。
 这样我们在要在事务中获取数据行,我们就能根据数据行的data_trx_id 和当前事务的read_view来判断此版本的数据在事务中是否可见。可见包括两层含义:
记录可见,且Deleted bit = 0;当前记录是可见的有效记录。
记录可见,且Deleted bit = 1;当前记录是可见的删除记录。此记录在本事务开始之前,已经删除。
 如果数据不可见我们需要去哪里找上一个版本的数据呢?
通过数据行的DB_ROLL_PTR字段去undo log信息中找到上一个版本的记录,再判断这个版本的数据是否可见,以此类推。
到这里,大概已经清楚了快照读中的"快照"是怎么生成的。

RC、RR区别

RR级别支持语句级别binlog,事务级创建read_view,gap锁导致不满足查询条件的锁不能提前释放。
 RC级别不支持语句级别binlog,语句级创建read_view,没有gap锁开销小,支持半一致读。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics