Innodb MVCC

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: mvcc标准机制多版本并发控制(Multiversion concurrency control)。当对数据进行写操作时,不允许对被操作数据进行读操作,这样会导致数据库并发性能低下。于是用mvcc在并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理,以降低写操作的堵塞而引发读操作的并发问题。

mvcc标准机制

多版本并发控制(Multiversion concurrency control)。

当对数据进行写操作时,不允许对被操作数据进行读操作,这样会导致数据库并发性能低下。于是用mvcc在并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理,以降低写操作的堵塞而引发读操作的并发问题。

mvcc在对插入、删除、更新、读取都有自己的标准机制。

标准插入流程

在我们自定义的表结构中,mysql会默认插入几个其他的字段,其中和mvcc相关的字段有DB_TRX_ID,DB_ROLL_PT,前者为数据行的版本号,后者为回滚版本号。

mysql的事务是全局的,每个事务都有一个全局的事务id,行版本号就是保存的当前事务的id号。例如执行事务:

begin; --事务id为1
insert into user(name,age) value ('zhangsan', 18);
insert into user(name,age) value ('lisi', 19);
commit;

假设此事务id为1,得到数据如下:

id name age DB_TRX_ID DB_ROLL_PT
1 zhangsan 18 1 null
2 lisi 19 1 null

这两条数据是在同一个id为1的事务中插入的,所以行版本号都为1,默认回滚版本号为null。

标准删除流程

例如删除id=2的记录:

begin; --事务id为22
delete from user where id=2;
commit;

此时在mvcc中并没有删除,而是将回滚版本号设置为当前事务的id号。行版本号不变。得到数据如下:

id name age DB_TRX_ID DB_ROLL_PT
1 zhangsan 18 1 null
2 lisi 19 1 22

标准修改流程

例如修改id=1的数据:

begin; --事务id为33
update user set age=19 where id=1;
commit;

此时是先将该记录复制为一条新的记录,行版本号设置为当前事务id,回滚版本号为null。然后在将原先的记录回滚版本号设置为当前事务id号,行版本号不变。

得到数据如下:

id name age DB_TRX_ID DB_ROLL_PT
1 zhangsan 18 1 33
2 lisi 19 1 22
2 zhangsan 19 33 null

标准查询流程

数据的查询规则:

1. 查找数据行版本号早于当前事务版本号的记录
    确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改的。

2. 查找删除版本号要么为null,要么大于当前事务版本号的记录
    确保取出来的记录在事务开启之前没有被删除。

例如查询:

begin; --事务id为44
select * from user;
commit;

根据规则,取出来的数据如下:

id name age DB_TRX_ID DB_ROLL_PT
2 lisi 19 1 22
2 zhangsan 19 33 null

验证查询规则

例如现在有两个事务如下:

事务1:
    begin; --1
    select * from user; --2
    commit;
    
事务2:
    begin; --3  事务id 33
    update user set age=28 where id=1; --4
    commit;

查询组合两套:

组合1:1-2-3-4-2
组合2:3-4-1-2

执行组合1

执行1-2后:
id name age DB_TRX_ID DB_ROLL_PT
1 zhangsan 18 1 null
2 lisi 19 1 null
执行3-4后:
id name age DB_TRX_ID DB_ROLL_PT
1 zhangsan 18 1 33
2 lisi 19 1 null
2 zhangsan 28 33 null
再执行2:
id name age DB_TRX_ID DB_ROLL_PT
2 lisi 19 1 null
2 zhangsan 28 33 null

取到的数据合理。

执行组合2

执行3-4后:
id name age DB_TRX_ID DB_ROLL_PT
1 zhangsan 18 1 33
2 lisi 19 1 null
2 zhangsan 28 33 null
再执行1-2后,假设此时事务id为55,获取到的数据为:
id name age DB_TRX_ID DB_ROLL_PT
2 lisi 19 1 null
2 zhangsan 28 33 null

此时获取到的数据包含3-4未提交的数据,这导致了脏读和不可重复读。

通过mvcc的标准机制导致了脏读和不可重复读,问题出在哪呢?

实际上innodb的mvcc并没有完全依据mvcc的标准流程,这种情况下并不是通过mvcc直接读取的,而是通过读取innodb 的undo log来获取。

即当发现被查询的结果集中有被上锁记录之后,这些被锁定的记录会转而去undo log中获取数据。

Undo Log

事务有时需要回滚操作,这时就需要undo。事务开始之前,首先将需操作的数据做备份,就是undo log。

undo log为了实现事务的原子性而出现的产物。如果事务处理过程中 出错或执行了ROLLBACK语句,Mysql可以利用undo log中的备份将数据逻辑恢复到事务开始之前的状态。

undo log可以用来实现多版本并发控制,undo log中的数据可作为数据旧版本快照供其他事务读取。

事务提交后并不能立即删除undo log,因为可能还有其他事务需要通过undo log来得到行记录之前的版本,因此事务提交时将undo log放入一个链表中,是否可以最终删除有purge线程来判断。

purge用于最终完成delete和update操作。这样设计是因为innodb支持mvcc,所以记录不能在事务提交时立即立即进行处理。这时其他事务可能正在引用这行,而是否可以删除通过purge来进行判断。若该记录已不被其他任何事务引用,那么就可以进行真正的delete操作。

Redo Log

redo log用来实现事务的持久性,innodb通过Force Log at Commit机制实现事务的持久性。即当事务提交时,必须先将该事务的所有日志写入到redo log中进行持久化,待事务的commit完成才算真正完成,这里的日志指重做日志,包括undo log和redo log两部分。

事务中操作的任何数据,将最新的数据备份到redo log,防止在发生故障时尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo
log进行重做,从而达到事务的持久化。

一旦事务成功提交且数据持久化落盘之后,此时Redo log中的对应事务数据记录就失去了意义,所以Redo log的写入是日志文件循环写入的。

快照读和当前读

快照读

普通的SELECT 就是快照读,innodb 快照读,数据的读取将由从undo log中读取。

当前读

当前读读取的数据是最新版本。通过锁机制来保证读取的数据无法通过其他事务进行修改
UPDATE 、DELETE 、INSERT 、SELECT … LOCK IN SHARE MODE 、SELECT … FOR UPDATE 都是当前读。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
6月前
|
存储 缓存 关系型数据库
⑩⑧【MySQL】InnoDB架构、事务原理、MVCC多版本并发控制
⑩⑧【MySQL】InnoDB架构、事务原理、MVCC多版本并发控制
218 0
|
5月前
|
存储 关系型数据库 MySQL
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
|
1月前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
265 4
|
2月前
|
关系型数据库 MySQL 数据库
InnoDB 的 MVCC 实现原理
InnoDB 的 MVCC 实现原理
42 0
|
4月前
|
存储 关系型数据库 文件存储
面试题MySQL问题之简单的SELECT操作在MVCC下加锁如何解决
面试题MySQL问题之简单的SELECT操作在MVCC下加锁如何解决
48 2
|
存储 算法 Oracle
PostgreSQL的MVCC vs InnoDB的MVCC
PostgreSQL的MVCC vs InnoDB的MVCC
94 0
PostgreSQL的MVCC vs InnoDB的MVCC
|
算法 关系型数据库 MySQL
简述Mysql InnoDB的MVCC机制
简述Mysql InnoDB的MVCC机制
159 0
简述Mysql InnoDB的MVCC机制
|
存储 SQL 算法
MySQL InnoDB MVCC机制
MySQL InnoDB MVCC机制
221 0
|
SQL 存储 算法
InnoDB解决幻读的方案--LBCC&MVCC
InnoDB解决幻读的方案--LBCC&MVCC
197 0
InnoDB解决幻读的方案--LBCC&MVCC
|
存储 关系型数据库 数据库