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

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

1、什么是多版本并发控制

多版本并发控制技术的英文全称是 Multiversion Concurrency Control,简称 MVCC数据库

多版本并发控制(MVCC) 是经过保存数据在某个时间点的快照来实现并发控制的。也就是说,无论事务执行多长时间,事务内部看到的数据是不受其它事务影响的,根据事务开始的时间不一样,每一个事务对同一张表,同一时刻看到的数据多是不同的。并发

简单来讲,多版本并发控制 的思想就是保存数据的历史版本,经过对数据行的多个版本管理来实现数据库的并发控制。这样咱们就能够经过比较版本号决定数据是否显示出来,读取数据的时候不须要加锁也能够保证事务的隔离效果。高并发

能够认为 多版本并发控制(MVCC) 是行级锁的一个变种,可是它在不少状况下避免了加锁操做,所以开销更低。虽然实现机制有所不一样,但大都实现了非阻塞的读操做,写操做也只锁定必要的行。性能

MySQL的大多数事务型存储引擎实现的都不是简单的行级锁。基于提高并发性能的考虑,它们通常都同时实现了多版本并发控制(MVCC)。不只是MySQL,包括Oracle、PostgreSQL等其余数据库系统也都实现了MVCC,但各自的实现机制不尽相同,由于MVCC没有一个统一的实现标准,典型的有乐观(optimistic)并发控制悲观(pessimistic)并发控制spa

2、多版本并发控制解决了哪些问题

1. 读写之间阻塞的问题

经过 MVCC 可让读写互相不阻塞,即读不阻塞写,写不阻塞读,这样就能够提高事务并发处理能力。设计

提升并发的演进思路:指针

  • 普通锁,只能串行执行;
  • 读写锁,能够实现读读并发;
  • 数据多版本并发控制,能够实现读写并发。

2. 下降了死锁的几率

由于 InnoDB 的 MVCC 采用了乐观锁的方式,读取数据时并不须要加锁,对于写操做,也只锁定必要的行。code

3. 解决一致性读的问题

一致性读也被称为快照读,当咱们查询数据库在某个时间点的快照时,只能看到这个时间点以前事务提交更新的结果,而不能看到这个时间点以后事务提交的更新结果。blog

3、快照读与当前读

快照读(SnapShot Read) 是一种一致性不加锁的读,是InnoDB并发如此之高的核心缘由之一索引

这里的 一致性是指,事务读取到的数据,要么是 事务开始前就已经存在的数据,要么是 事务自身插入或者修改过的数据

不加锁的简单的 SELECT 都属于快照读,例如:

`SELECT * FROM t WHERE id=1`

快照读 相对应的则是 当前读当前读就是读取最新数据,而不是历史版本的数据。加锁的 SELECT 就属于当前读,例如:

SELECT * FROM t WHERE id=1 LOCK IN SHARE MODE;

SELECT * FROM t WHERE id=1 FOR UPDATE;

4、InnoDB 的 MVCC 是如何工做的

1. InnoDB 是如何存储记录的多个版本的

事务版本号

每开启一个事务,咱们都会从数据库中得到一个事务 ID(也就是事务版本号),这个事务 ID 是自增加的,经过 ID 大小,咱们就能够判断事务的时间顺序。

行记录的隐藏列

InnoDB 的叶子段存储了数据页,数据页中保存了行记录,而在行记录中有一些重要的隐藏字段:

  • db_row_id:隐藏的行 ID,用来生成默认汇集索引。若是咱们建立数据表的时候没有指定汇集索引,这时 InnoDB 就会用这个隐藏 ID 来建立汇集索引。采用汇集索引的方式能够提高数据的查找效率。
  • db_trx_id:操做这个数据的事务 ID,也就是最后一个对该数据进行插入或更新的事务 ID。
  • db_roll_ptr:回滚指针,也就是指向这个记录的 Undo Log 信息。

InnoDB数据记录隐藏列

Undo Log

InnoDB 将行记录快照保存在了 Undo Log 里,咱们能够在回滚段中找到它们,以下图所示:

Undo Log回滚历史记录

从图中能看到回滚指针将数据行的全部快照记录都经过链表的结构串联了起来,每一个快照的记录都保存了当时的 db_trx_id,也是那个时间点操做这个数据的事务 ID。这样若是咱们想要找历史快照,就能够经过遍历回滚指针的方式进行查找。

2. 在 可重复读(REPEATABLE READ) 隔离级别下, InnoDB 的 MVCC 是如何工做的

查询(SELECT)

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

  1. InnoDB只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样能够确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的
  2. 行的删除版本要么未定义,要么大于当前事务版本号。这能够确保事务读取到的行,在事务开始以前未被删除

只有符合上述两个条件的记录,才能返回做为查询结果。

插入(INSERT)

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

删除(DELETE)

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

更新(UPDATE)

InnoDB为插入一行新记录,保存当前系统版本号做为行版本号,同时保存当前系统版本号到原来的行做为行删除标识。
保存这两个额外系统版本号,使大多数读操做均可以不用加锁。这样设计使得读数据操做很简单,性能很好,而且也能保证只会读取到符合标准的行。不足之处是每行记录都须要额外的存储空间,须要作更多的行检查工做,以及一些额外的维护工做。

5、总结

多版本并发控制(MVCC) 在必定程度上实现了读写并发,它只在 可重复读(REPEATABLE READ)提交读(READ COMMITTED) 两个隔离级别下工做。其余两个隔离级别都和 MVCC 不兼容,由于 未提交读(READ UNCOMMITTED),老是读取最新的数据行,而不是符合当前事务版本的数据行。而 可串行化(SERIALIZABLE) 则会对全部读取的行都加锁。

行锁,并发,事务回滚等多种特性都和MVCC相关。

相关文章
相关标签/搜索