innoDB通过mvcc(多版本并发控制)来提高并发能力,通过版本快照,保证大部分读操作都不用加锁,性能很好。缺点是缺点是没行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。

MVCC只在read commited和repeatable read隔离级别下生效,其他两个隔离级别与MVCC不兼容,因为read uncommited总是读最新的数据行,而串行化会对所有读取的行加锁。

innoDB的行数据有多个版本,每个版本有自己的row trx_id,每个事务或者语句有自己的一致性视图。普通查询是一致性读,一致性读会根据row trx_id和一致性视图确定数据版本的可见性。

  • 对于rr级别,查询只承认在事务启动前就已经提交完成的数据。
  • 对于rc级别,查询只承认在语句启动前就已经提交完成的数据。

实现上的区别:

  • rr级别,只需要在事务启动时创建一致性视图,事务的语句共用这一个一致性视图。
  • rc级别,每个语句执行前都会算出一个新的视图。

MVCC实现原理

innoDB 通过通过在每行记录后面保存两个隐藏列、read-view 和 undolog 版本链 实现MVCC。

这两个列,一个保存创建行时的事务版本号,一个保存删除行时的事务版本号。

innoDB每个事务都有一个唯一的事务ID,叫transaction ID。事务开始时向innoDB申请的,按申请顺序严格递增。

当创建一行记录时,会将事务ID赋值给这个行的创建事务版本号,记为row trx_id。

当更新时,同时更新两个事务版本号。

也就是说,表中每一行都有多个版本(row),每个版本都有自己的row trx_id,都对应一个事务ID。

在实现上,innoDB为每个事务生成一个数组,用来保存这个事务启动瞬间,当前正在”活跃“的所有事务ID。活跃是指启动了还没提交。

数组里最小值记为低水位,当前事务最大值+1记为高水位。

这个视图数组和高水位,就组成了当前事务的一致性视图(read-view)。

数据版本的可见性规则,就是基于数据的row trx_id 和一致性视图的对比结果得到的。

数据版本的可见性规则.png

对于当前事务的启动瞬间来说,一个数据版本的row trx_id,有以下几种可能:

  • 落在绿色部分,表示这个版本是已经提交的事务或自己生产的,可见。
  • 落在红色部分,表示这个版本是由将来启动的事务生成的,不可见。
  • 落在黄色部分,包括两种情况:

    • 若row trx_id不在数组内,表示这个版本是由未提交事务生成的,不可见;
    • 若row trx_id在数组内,表示这个版本是已经提交事务生成的,可见。

在不同隔离级别下的区别:

  • read commited 隔离级别下。

    • SELECT
      读取最新提交的版本数据。
  • repetable read 隔离级别下。

    • SELECT
      根据两个条件检查每条记录:
    1. 只查早于当前事务版本的数据行(也就是行的版本号小于或等于事务版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或修改过的。
    2. 行的删除版本要么未定义,要么大于当前事务版本号,这样可以确保事务读取的行,在事务开始前未被删除。
    • INSERT
      为新插入的每一行保存当前系统版本号作为行版本号。
    • DELETE
      为删除的每一行保存当前系统版本号作为行的删除版本号。
    • UPDATE
      innoDB为新插入的行,保存当前系统版本号作为行版本号,同时,保存当前系统版本号到原来行的删除版本号。

标签: none

添加新评论