首页 > 数据库 >浅析MySql中的MVCC机制

浅析MySql中的MVCC机制

时间:2023-02-06 13:56:40浏览次数:55  
标签:事务 快照 MVCC 浅析 trx 版本 MySql ReadView id

前言

本文将分析mvcc的机制和工作原理并举例说明。话不多说,直入主题

MVCC机制是什么

MVCC,英文全称Multiversion Concurrency Control,多版本并发控制。简单理解,就是相当于给我们的MySQL数据库拍个“快照”,定格某个时刻数据库的状态

为什么要拍快照?

为了保证事务启动到结束整个生命周期看到的数据是一致的, 一般有两种方案:

MySQL对数据“读-写”的时候,加锁,其他事务写这条数据时加上锁,其他事务读取的时候阻塞。
MySQL可以对事务启动的时候,对数据库拍个“快照”,那么事务运行过程中读取都从这个快照读取,不也是保证数据一致么。

第一种方案存在明显的问题,加锁会引发阻塞,从而降低数据库性能。而MySQL设计者们采用第二种,也就是大名鼎鼎的MVCC,它不仅能够解决不可重复读,还一定程度解决幻读的问题,因为你整个数据库快照都有了,你就知道那个时刻的数据了。

小结
MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突 ,做到即使有读写冲突时,也能做到不加锁 , 非阻塞并发读,而这个读指的就是快照读 , 而非当前读

什么是快照读和当前读

前文提到了快照读和当前读,那什么样的sql算是快照读,什么样又算是当前读呢?

快照读

快照读又叫普通读,也就是利用MVCC机制读取快照中的数据。不加锁的简单的SELECT 都属于快照读,比如这样:

SELECT * FROM user WHERE ...
  • 快照读是基于MVCC实现的,提高了并发的性能,降低开销
  • 大部分业务代码中的读取都属于快照读

当前读

当前读读取的是记录的最新版本,读取时会对读取的记录进行加锁, 其他事务就有可能阻塞。加锁的 SELECT,或者对数据进行增删改都会进行当前读。比如:

SELECT * FROM user LOCK IN SHARE MODE; # 共享锁
SELECT * FROM user FOR UPDATE; # 排他锁
INSERT INTO user values ... # 排他锁
DELETE FROM user WHERE ... # 排他锁
UPDATE user SET ... # 排他锁
  • update、delete、insert语句虽然没有select, 但是它们也会先进行读取,而且只能读取最新版本。

MVCC工作机制

前面说到快照是存储一份"照片",但是一个数据库如果100G数据,保存100G得多慢。接下来将讲解MVCC具体是如何工作的

数据的多个版本

首先MySQL innoDB存储引擎需要支持一条数据可以保留多个历史版本。怎么保留呢?那我们很自然的就想到了回滚使用到的undo_log
对于使用 InnoDB 存储引擎的数据库表,它的聚簇索引记录中都包含下面两个隐藏列:

  • trx_id,当一个事务对某条聚簇索引记录进行改动时,就会把该事务的事务 id 记录在 trx_id 隐藏列里;
  • roll_pointer,每次对某条聚簇索引记录进行改动时,都会把旧版本的记录写入到 undo 日志中,然后这个隐藏列是个指针,指向每一个旧版本记录,于是就可以通过它找到修改前的记录。
    InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id。它是在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的。

    如上图所示,针对id=1的这条数据,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被 roll_pointer 属性连接成一个链表,我们把这个链表称之为版本链,根据版本链就可以找到这条数据历史的版本。

一致性视图ReadView

ReadView就是事务在使用MVCC机制进行快照读操作时产生的一致性视图, 比如针对可重复读隔离级别,是在事务启动的时候,创建一个ReadView

  • trx_ids: 指的是在创建 ReadView 时,当前数据库中「活跃事务」的事务 id 列表,注意是一个列表, “活跃事务”指的就是,启动了但还没提交的事务。
  • min_trx_id: 指的是在创建 ReadView 时,当前数据库中「活跃事务」中事务 id 最小的事务,也就是 m_ids 的最小值。
  • max_trx_id:这个并不是 m_ids 的最大值,而是创建 ReadView 时当前数据库中应该给下一个事务的 id 值,也就是全局事务中最大的事务 id 值 + 1;
  • creator_trx_id :指的是创建该 ReadView 的事务的事务 id, 只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会为 事务分配事务id,否则在一个只读事务中的事务id值都默认为0。

对于当前事务的启动瞬间来说,读取的一个数据版本的trx_id,有以下几种可能:

  • 如果被访问版本的trx_id属性值与ReadView中的 creator_trx_id 值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
  • 如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;
  • 如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的;
  • 如果落在黄色部分,那就包括两种情况
    1. 若 数据的trx_id在trx_ids数组中,表示这个版本是由还没提交的事务生成的,不可见, 去读取这条数据的历史版本,这条数据的历史版本中都包含了事务id信息,去查找第一个不在活跃事务数组的版本记录。
    2. 若 数据的trx_id不在trx_ids数组中,表示这个版本是已经提交了的事务生成的,可见。

举例说明

insert into student(id, name, class) values(1, '张三', '一班')

可重复读隔离级别下

可重复读REPEATABLE READ 隔离级别的事务来说,只会在第一次执行查询语句时生成一个 ReadView ,之后的查询就不会重复生成了。


事务10和20均未提交,现在事务30执行select, 那么得到的结果是什么呢?

  1. 在执行select语句时会先生成一个ReadView,ReadView的trx_ids列表的内容就是[10, 20],min_trx_id为10,max_trx_id为21,creator_trx_id为0
  2. 然后从版本链中挑选可见的记录,从图中看出,最新版本的列name的内容是'王五',该版本的trx_id值为10,在trx_ids列表内,所以不符合可见性要求,根据roll_pointer跳到下一个版本。
  3. 下一个版本的列name的内容是'李四',该版本的trx_id值也为10,也在trx_ids列表内,所以也不符合要求,继续跳到下一个版本。
  4. 下一个版本的列name的内容是'张三',该版本的trx_id值为8,小于ReadView中的min_trx_id值10,说明已经提交了,那么最终返回'张三'

读已提交隔离级别下

读已提交READ COMMITTED是每次读取数据前都生成一个ReadView。基本的规则和流程与可重复读隔离级别一致,这里不做重复赘叙。

总结

本问重点介绍了MVCC机制,以及 MVCC 在 READ COMMITTD、 REPEATABLE READ 这两种隔离级别的事务在执行快照读操作时访问记录的版本链的过程。这样使不同事务的 读-写 、 写-读 操作并发执行,从而提升系统性能。

  • READ COMMITTD 在每一次进行普通SELECT操作前都会生成一个ReadView
  • REPEATABLE READ 只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复使用这个ReadView就好了。

标签:事务,快照,MVCC,浅析,trx,版本,MySql,ReadView,id
From: https://www.cnblogs.com/simplejavahome/p/17094947.html

相关文章

  • MySQL5.x msi自定义安装教程_也适用于8.x版本
    下载都会就跳过1、打开安装程序2、选择自定义安装方式3、选择要安装的MySQL版本4、承接3选择自定义安装路径和数据存储路径5、检查文件完整性6、无脑Next7、配置项作为服务......
  • 3 Mysql数据库总结
    1数据库索引索引就像书的目录,通过书的目录就准确的定位到了书籍具体的内容。我们知道目录只存放标题,浏览标题比翻书要快的多。就好比我们对id建立索引,我们查询id就只查询i......
  • MySQL笔记-8小时连接闲置超时
    最近发现之前部署在阿里云的一个web项目,每过一段时间就会报错,但是刷新下页面就会显示正常;在过了比较长的一段时间后,又会报同样的错误,如下:在网上查了下资料,原来是因为项目中......
  • TDSQL(MySQL)架构原理总结
    TDSQL(MySQL)架构原理总结一、思维导图![TDSQL架构原理总结](E:\教案笔记作业\自我总结笔记\typora\第三阶段\图片\TDSQL架构原理总结.png)二、核心架构1、架构概述TDSQL......
  • mysql排查事务及进程的语句
    查询事务SELECT*FROMinformation_schema.INNODB_TRX;查询正在锁的事务SELECT*FROMINFORMATION_SCHEMA.INNODB_LOCKS;查询等待锁的事务SELECT*FROMINFORMATION_SCHE......
  • 实战:第十六章:判断Mysql库中是否存在某表
    sql查询库中是否存在该表案例:SHOWTABLESINdreamweb_gjfgwWHERETables_in_dreamweb_gjfgw=‘g_app_data_service_log’格式:SHOWTABLESIN数据库名称WHERETab......
  • mysql从5.7升级到8.0的注意事项
    ####################################(1)sql_mode全局变量:在升级MySQL版本到8.0的过程中,需要关注sql_mode参数默认值的变化,8.0版本sql_mode不支持NO_AUTO_CREATE_USER,要避......
  • mysql:聊聊mysql中的锁八股文,锁分类,表锁(s锁,x锁,意向锁,自增锁,元数据锁)行锁(记录锁,间隙锁,临
    mysql:锁分类,表锁(s锁,x锁,意向锁,自增锁,元数据锁)行锁(记录锁,间隙锁,临键锁,插入意向锁)乐观锁,悲观锁,显示锁,隐式锁1从数据操作的类型划分:读锁、写锁读锁读锁:也称为共享锁、英文......
  • mysql:聊聊mysql学完之后心得,从哪里学,学哪些,怎么选课程,学到什么程度。
    mysql:聊聊mysql学完之后心得,从哪里学,学哪些,怎么选课程,学到什么程度。学习完一套课程之后习惯性总结一下。首先说一下,咕咕是跟着尚硅谷的康老师学习的mysql,大家想学习的话可......
  • java 和mysql 开发中的数据处理浅谈
    我们在开发过程中经常会用到java和mysql,两者都能处理数据。那么什么时候用这两个,或者在特定的情况下使用正确的工具,发挥工具的本身的特点提高开发的效率就显得尤为重要。j......