MySQL中InnoDB的多版本并发控制(MVCC)

mysql.png

简介

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

作为MySQL中使用最广泛的存储引擎,本文主要讨论的是InnoDB的多版本并发控制的实现

MVCC优缺点

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

MVCC的实现原理

undo log

为了便于理解MVCC的实现原理,这里简单介绍一下undo log的工作过程

在不考虑redo log 的情况下利用undo log工作的简化过程为:

序号 动作
1 开始事务
2 记录数据行数据快照到undo log
3 更新数据
4 将undo log写到磁盘
5 将数据写到磁盘
6 提交事务

1)为了保证数据的持久性数据要在事务提交之前持久化
2)undo log的持久化必须在在数据持久化之前,这样才能保证系统崩溃时,可以用undo log来回滚事务

Innodb中的隐藏列

Innodb通过undo log保存了已更改行的旧版本的信息的快照。
InnoDB的内部实现中为每一行数据增加了三个隐藏列用于实现MVCC。

列名 长度(字节) 作用
DB_TRX_ID 6 插入或更新行的最后一个事务的事务标识符。(删除视为更新,将其标记为已删除)
DB_ROLL_PTR 7 写入回滚段的撤消日志记录(若行已更新,则撤消日志记录包含在更新行之前重建行内容所需的信息)
DB_ROW_ID 6 行标识(隐藏单调自增id)

结构

数据列 .. DB_ROW_ID DB_TRX_ID DB_ROLL_PTR

MVCC工作过程

MVCC只在READ COMMITED 和 REPEATABLE READ 两个隔离级别下工作。READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行。而SERIALIZABLE 则会对所有读取的行都加锁

SELECT

InnoDB 会根据两个条件来检查每行记录:

  • InnoDB只查找版本(DB_TRX_ID)早于当前事务版本的数据行(行的系统版本号<=事务的系统版本号,这样可以确保数据行要么是在开始之前已经存在了,要么是事务自身插入或修改过的)
  • 行的删除版本号(DB_ROLL_PTR)要么未定义(未更新过),要么大于当前事务版本号(在当前事务开始之后更新的)。这样可以确保事务读取到的行,在事务开始之前未被删除。

INSERT

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

DELETE

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

UPDATE

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

参考资料

《高性能MYSQL》

MySQL 5.7参考手册

MVCC实现方式

转载请注明出处: https://www.jianshu.com/p/a3d49f7507ff