美文网首页
Mysql中的MVCC

Mysql中的MVCC

作者: kindol | 来源:发表于2018-09-25 21:37 被阅读0次

MVCC(Multi-Version Concurrency Control)即多版本并发控制
MySQL的大多数事务型(如InnoDB,Falcon等)存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,他们一般都同时实现了MVCC。当前不仅仅是MySQL,其它数据库系统(如Oracle,PostgreSQL)也都实现了MVCC。MVCC并没有一个统一的实现标准,所以不同的数据库,不同的存储引擎的实现都不尽相同。

MVCC在MYISAM用不了,行级锁用mysql的储存引擎实现而不是mysql服务器。

MVCC优缺点

MVCC在大多数情况下代替了行锁,实现了对读的非阻塞读不加锁,读写不冲突缺点是每行记录都需要额外的存储空间,需要做更多的行维护和检查工作

innodb的行结构

上面说到,实现MVCC需要innodb有额外的空间,其存在一些额外的字段如下:

列名 作用
DB_TRX_ID 插入或更新行的最后一个事务的事务标识符,每处理一个事务,值+1。(删除视为更新,将其标记为已删除
DB_ROLL_PTR 指向当前记录项的rollback segment的undo log记录,找之前版本的数据就是通过这个指针
DELETE_BIT 标识该记录是否被删除,这里的不是真正的删除数据,而是标志出来的删除。真正意义的删除是在commit的时候
DB_ROW_ID 用于聚簇索引隐式产生的索引行(隐藏单调自增id)

简述下undo log(不考虑redo log)的工作过程

  1. 开始事务
  2. 记录数据行数据快照到undo log
  3. 更新数据(此时在缓存中操作)
  4. 将undo log写到磁盘
  5. 将数据写到磁盘
  6. 提交事务

undo log的持久化必须在在数据持久化之前,这样才能保证系统崩溃时,可以用undo log来回滚事务

各种语句的执行过程

  • insert

    InnoDB为每个新增行记录当前系统版本号作为DB_TRX_ID

    比如插入一条记录, 事务id 假设是1,那么记录如下:(创建版本号就是事务版本号)

    id name DB_TRX_ID DELETE_BIT
    1 test 1
  • update

    InnoDB复制了一行。先标记旧的记录为已删除(DELETE_BIT)并且版本号更新为当前事务版本号,然后插入一行新的记录的方式。

    比如,针对上面的记录,当前事务id为2,更新name字段:

    id name DB_TRX_ID DELETE_BIT
    1 test 2 1
    1 test2 2
  • delete

    设当前版本号为3,InnoDB为每个删除行的记录当前系统版本号作为行的删除ID,并且设置DELETE_BIT,比如:

    delete from table a where id = 1;

    id name DB_TRX_ID DELETE_BIT
    1 test2 3 1
  • select

    Innodb检查每行数据,确保他们符合两个标准:

    1、InnoDB只查找记录行中版本 <= 当前事务版本的数据行,这确保当前事务读取的行都是事务之前已经存在的,或者是由当前事务创建或修改的行

    2、行的删除操作的版本一定是未定义的或者>当前事务的版本号确定了当前事务开始之前,行没有被删除

    通过版本号来减少锁的争用,符合了以上两点则返回查询结果。

说明:

  • insert操作时“创建时间”=DB_ROW_ID,这时,“删除时间 ”是未定义的
  • update时,复制新增行的“创建时间”=DB_ROW_ID,删除时间未定义,旧数据行“创建时间”不变,删除时间=当前事务的DB_ROW_ID
  • delete操作,相应数据行的“创建时间”不变,删除时间=该事务的DB_ROW_ID
  • select操作对两者都不修改,只读相应的数据
  • 只有read-committed和repeatable-read两种事务隔离级别才能使用MVCC;read-uncommited由于是读到未提交的,所以不存在版本的问题;而serializable则会对所有读取的行加锁。

一些重点

要知道的,MVCC机制下,会在更新前建立undo log,根据各种策略读取时非阻塞就是MVCC,undo log中的行就是MVCC中的多版本

而undo log这个关键的东西,记载的内容是串行化的结果,记录了多个事务的过程,不属于多版本共存。

这么一看,似乎mysql的mvcc也并没有所谓的多版本共存

一些问题

  • 如果select出来的数据再进行对这条数据update的时候,数据已经过期,mysql是怎么操作的

首先需要知道的是,修改时Copy出当前版本随意修改,各个事务之间无干扰保存时比较版本号,如果成功(commit),则覆盖原记录;失败则放弃copy(rollback),听起来很有乐观锁的感觉,InnoDB的实现方式是:

  1. 事务以排他锁的形式修改原始数据
  2. 修改前的数据存放于undo log,通过回滚指针与主数据关联
  3. 修改成功(commit),数据放到redo log中,失败则恢复undo log中的数据(rollback)

从上面可以看到,进行数据更新依旧会有加锁,但只在于修改的时刻

推荐阅读:
https://blog.csdn.net/chen77716/article/details/6742128

相关文章

网友评论

      本文标题:Mysql中的MVCC

      本文链接:https://www.haomeiwen.com/subject/exlroftx.html