mysql的MVCC多版本并发控制的实现


Posted in MySQL onApril 14, 2021

1 什么是MVCC

MVCC全称是: Multiversion concurrency control,多版本并发控制,提供并发访问数据库时,对事务内读取的到的内存做处理,用来避免写操作堵塞读操作的并发问题。

举个例子,程序员A正在读数据库中某些内容,而程序员B正在给这些内容做修改(假设是在一个事务内修改,大概持续10s左右),A在这10s内 则可能看到一个不一致的数据,在B没有提交前,如何让A能够一直读到的数据都是一致的呢?

有几种处理方法,第一种: 基于锁的并发控制,程序员B开始修改数据时,给这些数据加上锁,程序员A这时再读,就发现读取不了,处于等待情况,只能等B操作完才能读数据,这保证A不会读到一个不一致的数据,但是这个会影响程序的运行效率。还有一种就是:MVCC,每个用户连接数据库时,看到的都是某一特定时刻的数据库快照,在B的事务没有提交之前,A始终读到的是某一特定时刻的数据库快照,不会读到B事务中的数据修改情况,直到B事务提交,才会读取B的修改内容。

一个支持MVCC的数据库,在更新某些数据时,并非使用新数据覆盖旧数据,而是标记旧数据是过时的,同时在其他地方新增一个数据版本。因此,同一份数据有多个版本存储,但只有一个是最新的。

MVCC提供了 时间一致性的 处理思路,在MVCC下读事务时,通常使用一个时间戳或者事务ID来确定访问哪个状态的数据库及哪些版本的数据。读事务跟写事务彼此是隔离开来的,彼此之间不会影响。假设同一份数据,既有读事务访问,又有写事务操作,实际上,写事务会新建一个新的数据版本,而读事务访问的是旧的数据版本,直到写事务提交,读事务才会访问到这个新的数据版本。

MVCC有两种实现方式,第一种实现方式是将数据记录的多个版本保存在数据库中,当这些不同版本数据不再需要时,垃圾收集器回收这些记录。这个方式被PostgreSQL和Firebird/Interbase采用,SQL Server使用的类似机制,所不同的是旧版本数据不是保存在数据库中,而保存在不同于主数据库的另外一个数据库tempdb中。第二种实现方式只在数据库保存最新版本的数据,但是会在使用undo时动态重构旧版本数据,这种方式被Oracle和MySQL/InnoDB使用。

2、InnoDB的MVCC实现机制

  MVCC可以认为是行级锁的一个变种,它可以在很多情况下避免加锁操作,因此开销更低。MVCC的实现大都都实现了非阻塞的读操作,写操作也只锁定必要的行。InnoDB的MVCC实现,是通过保存数据在某个时间点的快照来实现的。一个事务,不管其执行多长时间,其内部看到的数据是一致的。也就是事务在执行的过程中不会相互影响。下面我们简述一下MVCC在InnoDB中的实现。

  InnoDB的MVCC,通过在每行记录后面保存两个隐藏的列来实现:一个保存了行的创建时间,一个保存行的过期时间(删除时间),当然,这里的时间并不是时间戳,而是系统版本号,每开始一个新的事务,系统版本号就会递增。在RR隔离级别下,MVCC的操作如下:

select操作。

InnoDB只查找版本早于(包含等于)当前事务版本的数据行。可以确保事务读取的行,要么是事务开始前就已存在,或者事务自身插入或修改的记录。

行的删除版本要么未定义,要么大于当前事务版本号。可以确保事务读取的行,在事务开始之前未删除。

insert操作。将新插入的行保存当前版本号为行版本号。

delete操作。将删除的行保存当前版本号为删除标识。

update操作。变为insert和delete操作的组合,insert的行保存当前版本号为行版本号,delete则保存当前版本号到原来的行作为删除标识。

  由于旧数据并不真正的删除,所以必须对这些数据进行清理,innodb会开启一个后台线程执行清理工作,具体的规则是将删除版本号小于当前系统版本的行删除,这个过程叫做purge。

3、简单的小例子

create table yang( 
    id int primary key auto_increment, 
    name varchar(20));
}

  假设系统的版本号从1开始.

INSERT

  InnoDB为新插入的每一行保存当前系统版本号作为版本号.
  第一个事务ID为1;

start transaction;
insert into yang values(NULL,'yang') ;
insert into yang values(NULL,'long');
insert into yang values(NULL,'fei');
commit;

  对应在数据中的表如下(后面两列是隐藏列,我们通过查询语句并看不到)

mysql的MVCC多版本并发控制的实现

SELECT

 InnoDB会根据以下两个条件检查每行记录:
  a.InnoDB只会查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的.
  b.行的删除版本要么未定义,要么大于当前事务版本号,这可以确保事务读取到的行,在事务开始之前未被删除.
 只有a,b同时满足的记录,才能返回作为查询结果.

DELETE

 InnoDB会为删除的每一行保存当前系统的版本号(事务的ID)作为删除标识.
  看下面的具体例子分析:
  第二个事务,ID为2;

start transaction;
select * from yang;  //(1)
select * from yang;  //(2)
commit;

假设1

  假设在执行这个事务ID为2的过程中,刚执行到(1),这时,有另一个事务ID为3往这个表里插入了一条数据;
  第三个事务ID为3;

start transaction;
insert into yang values(NULL,'tian');
commit;

  这时表中的数据如下:

mysql的MVCC多版本并发控制的实现

  然后接着执行事务2中的(2),由于id=4的数据的创建时间(事务ID为3),执行当前事务的ID为2,而InnoDB只会查找事务ID小于等于当前事务ID的数据行,所以id=4的数据行并不会在执行事务2中的(2)被检索出来,在事务2中的两条select 语句检索出来的数据都只会下表:

mysql的MVCC多版本并发控制的实现

 假设2

  假设在执行这个事务ID为2的过程中,刚执行到(1),假设事务执行完事务3后,接着又执行了事务4;
  第四个事务:

start   transaction;  
delete from yang where id=1;
commit;

  此时数据库中的表如下:

mysql的MVCC多版本并发控制的实现

  接着执行事务ID为2的事务(2),根据SELECT 检索条件可以知道,它会检索创建时间(创建事务的ID)小于当前事务ID的行和删除时间(删除事务的ID)大于当前事务的行,而id=4的行上面已经说过,而id=1的行由于删除时间(删除事务的ID)大于当前事务的ID,所以事务2的(2)select * from yang也会把id=1的数据检索出来.所以,事务2中的两条select 语句检索出来的数据都如下:

mysql的MVCC多版本并发控制的实现

UPDATE
  InnoDB执行UPDATE,实际上是新插入了一行记录,并保存其创建时间为当前事务的ID,同时保存当前事务ID到要UPDATE的行的删除时间.

 假设3
  假设在执行完事务2的(1)后又执行,其它用户执行了事务3,4,这时,又有一个用户对这张表执行了UPDATE操作:
  第5个事务:

start  transaction;
update yang set name='Long' where id=2;
commit;

  根据update的更新原则:会生成新的一行,并在原来要修改的列的删除时间列上添加本事务ID,得到表如下:

mysql的MVCC多版本并发控制的实现

  继续执行事务2的(2),根据select 语句的检索条件,得到下表:

mysql的MVCC多版本并发控制的实现

  还是和事务2中(1)select 得到相同的结果.

到此这篇关于mysql的MVCC多版本并发控制的实现的文章就介绍到这了,更多相关mysql MVCC多版本并发控制内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
MySQL主从搭建(多主一从)的实现思路与步骤
May 13 MySQL
MySQL 常见的数据表设计误区汇总
Jun 07 MySQL
MySQL配置主从服务器(一主多从)
Aug 07 MySQL
MySQL数据库10秒内插入百万条数据的实现
Nov 01 MySQL
MySQL数据库⾼可⽤HA实现小结
Jan 22 MySQL
SQL注入篇学习之盲注/宽字节注入
Mar 03 MySQL
MySQL学习必备条件查询数据
Mar 25 MySQL
mysql使用instr达到in(字符串)的效果
Apr 03 MySQL
mysql的单列多值存储实例详解
Apr 05 MySQL
Mysql中常用的join连接方式
May 11 MySQL
MySQL数据管理操作示例讲解
Dec 24 MySQL
MySQL索引失效十种场景与优化方案
May 08 MySQL
mysql查询的控制语句图文详解
详解MySQL InnoDB存储引擎的内存管理
MySQL Innodb关键特性之插入缓冲(insert buffer)
Apr 08 #MySQL
如何使用Maxwell实时同步mysql数据
MySQL创建索引需要了解的
Apr 08 #MySQL
MySQL 使用SQL语句修改表名的实现
详解Mysql 函数调用优化
Apr 07 #MySQL
You might like
discuz Passport 通行证 整合笔记
2008/06/30 PHP
php页面跳转代码 输入网址跳转到你定义的页面
2013/03/28 PHP
PHP Cookie的使用教程详解
2013/06/03 PHP
PHP结合Jquery和ajax实现瀑布流特效
2016/01/07 PHP
Tinymce+jQuery.Validation使用产生的BUG
2010/03/29 Javascript
浅谈JavaScript之事件绑定
2013/07/08 Javascript
一个很有趣3D球状标签云兼容IE8
2014/08/22 Javascript
JavaScript对象数组排序函数及六个用法
2015/12/23 Javascript
百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换
2016/02/19 Javascript
AngularJs学习第八篇 过滤器filter创建
2016/06/08 Javascript
Vuejs 组件——props数据传递的实例代码
2017/03/07 Javascript
JavaScript中利用Array filter() 方法压缩稀疏数组
2018/02/24 Javascript
Vue的路由动态重定向和导航守卫实例
2018/03/17 Javascript
webpack4 CSS Tree Shaking的使用
2018/09/03 Javascript
从零开始在NPM上发布一个Vue组件的方法步骤
2018/12/20 Javascript
javascript+css实现进度条效果
2020/03/25 Javascript
Python的Flask开发框架简单上手笔记
2015/11/16 Python
Python爬虫实例_城市公交网络站点数据的爬取方法
2018/01/10 Python
通过python将大量文件按修改时间分类的方法
2018/10/17 Python
python实现自动化上线脚本的示例
2019/07/01 Python
pandas中read_csv的缺失值处理方式
2019/12/19 Python
python3通过udp实现组播数据的发送和接收操作
2020/05/05 Python
python 瀑布线指标编写实例
2020/06/03 Python
Born鞋子官网:Born Shoes
2017/04/06 全球购物
UNOde50美国官网:西班牙珠宝品牌
2020/08/15 全球购物
教师求职信范文分享
2013/12/27 职场文书
运动会广播稿300字
2014/01/10 职场文书
班级口号大全
2014/06/09 职场文书
手术室护士个人总结
2015/02/13 职场文书
学校后勤工作总结2015
2015/05/15 职场文书
飞越疯人院观后感
2015/06/09 职场文书
高效课堂教学反思
2016/02/24 职场文书
详解前端任务构建利器Gulp.js使用指南
2021/04/30 Javascript
PyTorch 实现L2正则化以及Dropout的操作
2021/05/27 Python
一篇文章带你了解Python和Java的正则表达式对比
2021/09/15 Python
Vue的过滤器你真了解吗
2022/02/24 Vue.js