MySQL多版本并发控制原理-MVCC
MySQL多版本并发控制原理-MVCC
MySQL的多版本并发控制(MVCC)是一种重要的并发控制机制,它通过维护数据的多个版本来解决读写冲突,从而提高数据库的并发性能。本文将详细介绍MVCC的工作原理,并通过具体案例帮助读者理解其核心概念。
MVCC实现的目的
MVCC多版本并发控制实现的主要目的,就是为了解决数据库的读与写的并发冲突,提高并发性能。核心就是说,在读与写冲突的时候,尽最大可能不去加锁。
基于数据库的读与写实际上区分为几种:
第一:读与读
读与读实际并不会存在并发冲突,因为读并不涉及到数据库数据的变更。
第二:写与写
写与写实际也不会存在问题。因为写是一定会涉及数据库数据的变更的。所以当两个线程过来并发写的时候,那只能通过锁来解决,哪个线程拿到了锁,那就哪个线程去写。
第三:读与写
读与写是我们在数据库的操作中,需要考虑最多的情况了。因为在实际的业务中,基本都是读多写少的业务。所以在这种情况 下,我们就需要着重考虑如何来提高数据库的性能了。
为什么读与写我们不直接使用锁来处理。谁拿到了锁谁就来写,这里其实很好回答,就是为了性能。锁是影响整个数据库性能的最大问题之一。
MVCC的原理
简单的来说:MVCC就是将一条数据的所有历史版本都以链表的形式存储。不同的事务可以来访问整个链表中不同时期的数据版本快照。
这样的话。对于读来说可以去读取对应历史的版本,而写的话就可以写最新版本。互不冲突。
对于实现这样一个链表。mysql会基于每条数据来增加两个重要的字段
DB_TRX_ID: 创建或者修改数据的事务ID
这个字段记录的就是哪个事务来创建的这条数据。事务ID是系统分配的一个自增的数据,永远都从小到大。
DB_ROLL_PTR:回滚指针,指向记录的上一个版本。
这个字段记录的就是前一个事务的数据
例子
我们以一个实际的案例展示一下它的显示形式
下面这个图里面,每一行代表的都是这一条数据 的一个版本。
这个表里有2个字段 id 、name 。 另外两个显示的字段DB_TRX_ID DB_ROLL_PTR 是系统字段。
- 第一次事务,事务id : 100 进行修改name 为 mysql
- 第二个事务,事务id : 200 来修改name 为sql 时。数据库表中的数据被修改成 sql ,但事务200的DB_ROLL_PTR指针会指向事务100的修改记录,这样就形成了一个链路。
- 第三个事务,事务id : 300 来修改name 为mvvc .此时事务id300的修改就是最新数据。且DB_ROLL_PTR会指向事务200的数据。
整个的MVCC存储链路就是这样的一个原理。
但我们会想到。为什么数据库我看到的永远都是最新的。当然,这里的链路数据是存储在undo日志中的。
所以当事务进行回滚时,就可以通过这个链路找到对应的事务数据。
如何来通过链路找到对应的事务数据
我们来了解一下2个概念
当前读
当前读就是读取数据的最新版本。其他的事务不能修改记录。
例如:insert 、update 、delete 、select ... for update 等这些执行语句都是当前读,读取数据的最新版本。
快照读
快照读就是读取MVCC版本链路中的某一个版本,不需要加锁
例如:select 读取的就是当前事务中的快照数据。
read view读视图
读视图是一个很重要的概念,它才是如何找到对应版本的事务的数据核心。
所谓读视图,实际上是记录并维护了系统当前事务的活跃事务id .哪些是活跃事务id ? (创建并未提交的事务)
我们看一下实际的案例如何来寻找对应版本数据:
下面的图中:有3个事务 100 、200 、300 ,活跃事务有 205 、255 、300 。也就是说只有300是未提交的。100和200 已经提交了。
- 当新事务301来查询数据时,首先读取了事务id=300的数据,也就是mvcc这条数据。但是事务301发现事务300是活跃事务(未提交事务),那事务300的值mvcc是不可见的。所以向下读取undo日志进行数据查找 。
- 通过事务id=300的这条数据的DB_ROLL_PTR指针在undo日志中找到了事务id=200这条数据
- 读取了事务id=200这条数据,发现事务id=200这条事务已经提交了,所以获取事务id=200这条数据。也就是值为:sql.
第二个例子:
下面的图中:有3个事务 100 、200 、300 ,活跃事务有 205 、255 、300 。也就是说只有300是未提交的。100和200 已经提交了。
- 当历史事务150来查询数据时,首先读取了事务id=300的数据,也就是mvcc这条数据。但是事务150发现事务300是活跃事务(未提交事务),那事务300的值mvcc是不可见的。所以向下读取undo日志进行数据查找 。
- 通过事务id=300的这条数据的DB_ROLL_PTR指针在undo日志中找到了事务id=200这条数据
- 读取了事务id=200这条数据,发现事务id=200这条事务已经提交了,但是事务200大于事务150.也就是说事务200是在150后面产生的事务。那对于事务150来说,也是不可见的。所以继续向下读取undo日志进行数据查找
- 通过事务id=200的这条数据的DB_ROLL_PTR指针在undo日志中找到了事务id=100这条数据
- 与上面的流程一样。找到事务id100且已提交,于是读取数据为 : mysql
当然了。如果是事务300来读取数据,那返回 的数据肯定 是其本身的数据了。也就是 mvcc
总结
总体来说,MVCC是一种强大的多版本并发控制,能解决mysql读写冲突中的并发效率问题。尽可能少的去加锁,来提高并发效率。
本文简明扼要的介绍了MVCC的目的及实现原理并通过实际的案例来说明了如何去查找快照。很好的理解MVCC的版本控制是如何做到的。