InnoDB MVCC实现原理及源码解析

  

1,原理介绍

  

数据多版本(MVCC)是MySQL实现高性能的一个主要的一个主要方式,通过对普通的选择不加锁,直接利用MVCC读取指版本的值,避免了对数据重复加锁的过程.InnoDB支持MVCC多版本,其中钢筋混凝土和RR隔离级别是利用一致的阅读观点方式支持的,即在某个时刻对事物系统打快照记下所有活跃读写事务ID,之后读操作根据事务ID与快照中的事务ID进行比较,判断可见性。

  

2, InnoDB数据行结构

  

行结构中,除了用户定义的列外还有3个系统列:DATA_ROW_ID, DATA_TRX_ID, DATA_ROLL_PTR,如果表没有定义主键那么DATA_ROW_ID作为主键列,否则行结构中没有DATA_ROW_ID列。其中:

  
 <代码> DATA_TRX_ID:修改该行数据的事务的ID
  
  DATA_ROLL_PTR:指向该行回滚段的指针。 
  

整个MVCC实现,关键靠这2个字段来完成。

  

3, read视图原理流程
 InnoDB MVCC实现原理及源码解析“> <br/> 4, read视图解读</p>
  <p> 1)读取视图是和SQL语句绑定的,在每个SQL语句执行前申请或获取(RR隔离级别:事务第一个选择申请,之后都用这个;钢筋混凝土隔离级别:每个选择都会申请)</p>
  <p> 2)阅读视图结构</p>
  <pre> <代码> struct read_view_t {
  ulint类型;/* ! & lt;VIEW_NORMAL VIEW_HIGH_GRANULARITY */undo_no_t undo_no;/* ! & lt;0或者类型
  VIEW_HIGH_GRANULARITY
  事务undo_no当这个high-granularity
  一致的阅读创建视图*/trx_id_t low_limit_no;/* ! & lt;视图不需要看到撤销
  日志事务的事务数量
  (& lt;)是严格小于这个值:
  在清洗,如果不需要可以删除呢
  视图*/trx_id_t low_limit_id;/* ! & lt;阅读不应该看到任何事务
  trx id祝辞=这个值。换句话说,
  这是“高水标”。*/trx_id_t up_limit_id;/* ! & lt;阅读应该看到所有trx id
  (& lt;)严格小于这个值。
  换句话说,
  这是“低水位标志”。*/ulint n_trx_ids;/* ! & lt;细胞数量trx_ids数组*/trx_id_t * trx_ids;/* ! & lt;阅读应该额外trx id
  没有看到:通常情况下,这些是读写
  活动事务时阅读
  被序列化,除了读事务
  本身;在这个数组在trx id
  降序排列。这些trx_ids应该
  “低”和“高”之间的水痕,
  也就是说,up_limit_id和low_limit_id。*/trx_id_t creator_trx_id;/* ! & lt;硫氧还蛋白的id创建交易,或
  0用于清洗*/UT_LIST_NODE_T (read_view_t) view_list;/* ! & lt;阅读列表视图trx_sys */};</代码> </>之前
  <p>主要包括3个成员{low_limit_id、up_limit_id trx_ids}。</p>
  <pre> <代码> low_limit_id:表示创建阅读视图时,当前事务活跃读写链表最大的事务ID,即最近创建的除自身外最大的事务ID
  
  up_limit_id:表示创建阅读视图时,当前事务活跃读写链表最小的事务ID。
  
  trx_ids:创建阅读视图时,活跃事务链表里所有事务ID </代码> </pre>
  <p> 3)对于小于等于RC的隔离级别,每次SQL语句结束后都会调用read_view_close_for_mysql将阅读视图从事务中删除,这样在下一个SQL语句启动时,会判断trx→read_view为NULL,从而重新申请。对于RR隔离级别,则SQL语句结束后不会删除read_view,从而下一个SQL语句时,使用上次申请的,这样保证事务中读的视图都一样,从而实现可重复读的隔离级别。</p>
  <p> 4)对于可见性判断,分配聚集索引和二级索引。聚集索引:</p>
  <pre> <代码>记录的DATA_TRX_ID & lt;视图→up_limit_id:在创建阅读视图时,修改该记录的事务已提交,该记录可见</代码> </pre>
  <p> DATA_TRX_ID祝辞=视图→low_limit_id:当前事务启动后被修改,该记录不可见</p>
  <p> DATA_TRX_ID位于(视图→up_limit_id,视图→low_limit_id):需要在活跃读写事务数组查找trx_id是否存在,如果存在,记录对于当前阅读视图是不可见的。</p>
  <p>二级索引:</p>
  <pre> <代码>由于InnoDB的二级索引只保存页面最后更新的trx_id,当利用二级索引进行查询的时候,如果页面的trx_id小于视图→up_limit_id,可以直接判断页面的所有记录对于当前视图是可见的,否则需要回聚集索引进行判断。</代码> </pre>
  <p> 5)如果记录对于视图不可见,需要通过记录的DB_ROLL_PTR指针遍历历史列表构造当前视图可见版本数据</p>
  <p> 6)开始事务和开始语句执行后并没有在innodb层分配事务ID、回滚段,read_view,将事务放到读写事务链表等,这个操作需要第一个SQL语句调用函数trx_start_low来完成,这个需要注意。</p><h2 class=InnoDB MVCC实现原理及源码解析