MySQL MVCC机制深入

2024-06-01 01:58

本文主要是介绍MySQL MVCC机制深入,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

MySQL MVCC机制

什么是MVCC

MVCC (Multiversion Concurrency Control) 中文全程叫多版本并发控制,是现代数据库(包括 MySQLOraclePostgreSQL 等)引擎实现中常用的处理读写冲突的手段,目的在于提高数据库高并发场景下的吞吐性能

如此一来不同的事务在并发过程中,SELECT 操作可以不加锁而是通过 MVCC 机制读取指定的版本历史记录,并通过一些手段保证保证读取的记录值符合事务所处的隔离级别,从而解决并发场景下的读写冲突。

InnoDB 中的 MVCC

  1. MySQLInnoDB 引擎支持 MVCC
  2. 应对高并发事务, MVCC 比单纯的加行锁更有效, 开销更小
  3. MVCC 在读已提交(Read Committed)和可重复读(Repeatable Read)隔离级别下起作用
  4. MVCC 既可以基于乐观锁又可以基于悲观锁来实现

InnoDB MVCC 实现原理

begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第 一个操作InnoDB表的语句,事务才真正启动,才会向mysql申请事务ID,mysql内部是严格照事务的启动顺序来分配事务ID的事务ID依次递增

InnoDBMVCC 的实现方式为:每一行记录都有两个隐藏列:DATA_TRX_IDDATA_ROLL_PTR(如果没有主键,则还会多一个隐藏的主键列)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-51oF0K3l-1588519526486)(https://i.loli.net/2020/05/03/zj6l4avrf9VCNsI.png)]

  • DATA_TRX_ID

    记录最近更新这条行记录的事务 ID,大小为 6 个字节

  • DATA_ROLL_PTR

    表示指向该行回滚段(rollback segment)的指针,大小为 7 个字节,InnoDB 便是通过这个指针找到之前版本的数据。该行记录上所有旧版本,在 undo 中都通过链表的形式组织。

  • DB_ROW_ID

    行标识(隐藏单调自增 ID),大小为 6 字节,如果表没有主键,InnoDB 会自动生成一个隐藏主键,因此会出现这个列。另外,每条记录的头信息(record header)里都有一个专门的bitdeleted_flag)来表示当前记录是否已经被删除。

举例说明

有一张表:user字段有id,name

事务执行表:

#Transaction 100#Transaction 200#Transaction 300#selectRR-ReadViewRC-ReadView
begin;begin;begin;begin;
update user set name=‘zxl300’ where id=1;
commit;
select name from user where id=1;[100,200],300 rs:zxl300[100,200],300 rs:zxl300
update user set name=‘zxl1’ where id=1;
update user set name=‘zxl2’ where id=1;
select name from user where id=1;[100,200],300 rs:zxl300[100,200],300 rs:zxl300
commit;update user set name=‘zxl3’ where id=1;
update user set name=‘zxl4’ where id=1;
select name from user where id=1;[100,200],300 rs:zxl300[200],300 rs:zxl2
commit;

如何组织 Undo Log 链

  1. userid=1 的这行记录加排他锁。
  2. 把该行原本的值拷贝到 undo log 中,DB_TRX_IDDB_ROLL_PTR 都不动
  3. 修改该行的值这时产生一个新版本,更新 DATA_TRX_ID 为修改记录的事务 ID,将 DATA_ROLL_PTR 指向刚刚拷贝到 undo log 链中的旧版本记录,这样就能通过 DB_ROLL_PTR 找到这条记录的历史版本。如果对同一行记录执行连续的 UPDATEUndo Log 会组成一个链表,遍历这个链表可以看到这条记录的变迁
  4. 记录 redo log,包括 undo log 中的修改

那么 INSERTDELETE 会怎么做呢?其实相比 UPDATE 这二者很简单,INSERT 会产生一条新纪录,它的 DATA_TRX_ID 为当前插入记录的事务 IDDELETE 某条记录时可看成是一种特殊的 UPDATE,其实是软删,真正执行删除操作会在 commit 时,DATA_TRX_ID 则记录下删除该记录的事务 ID

DB_TRX_ID 只有insert/update/delete时创建

ReadView 生成规则

当执行查询SQL时会生成一致性视图ReadView,它由执行查询时所有未提交的事务ID数组(数组中最小的id为mid_id)和已创建的最大事务ID(max_id)组成,查询的数据结果需要跟ReadView做比对从而得到快照结果。

RU 下的 ReadView 生成

RU 隔离级别下,直接读取版本的最新记录就 OK,对于 SERIALIZABLE 隔离级别,则是通过加锁互斥来访问数据,因此不需要 MVCC 的帮助。因此 MVCC 运行在 RCRR 这两个隔离级别下,当 InnoDB 隔离级别设置为二者其一时,在 SELECT 数据时就会用到版本链

核心问题是版本链中哪些版本对当前事务可见?

InnoDB 为了解决这个问题,设计了 ReadView(可读视图)的概念。

RR 下的 ReadView 生成

RR 隔离级别下,每个事务 touch first read 时(本质上就是执行第一个 SELECT 语句时,后续所有的 SELECT 都是复用这个 ReadView,其它 update, delete, insert 语句和一致性读 snapshot 的建立没有关系),会将当前系统中的所有的活跃事务拷贝到一个列表生成ReadView

RC 下的 ReadView 生成

RC 隔离级别下,每个 SELECT 语句开始时,都会重新将当前系统中的所有的活跃事务拷贝到一个列表生成 ReadView。二者的区别就在于生成 ReadView 的时间点不同,一个是事务之后第一个 SELECT 语句开始、一个是事务中每条 SELECT 语句开始。

MVCC 判断流程

根据ReadView生成规则可以将数据分为三个区域,小于最小未提交事务Id的称为已提交事务大于未提交事务最小ID小于已创建最大事务ID称为未提交与已提交事务,大于已创建最大事务ID称为未开始事务

https://c01.gaitubao.net/gaitubao_Fla_tpH0xuEv1zaf9Ktn958KTlUs.png?watermark/1/image/aHR0cHM6Ly9jMDEuZ2FpdHViYW8ubmV0L2dhaXR1YmFvX0ZvNlZaakFzb3lCN1ZOVU5zYXQ3cVJMNEt4QzAucG5nP2ltYWdlTW9ncjIvcm90YXRlLzA=/gravity/Center/dx/0/dy/0
  1. 如果ROW的ID(DB_TRX_ID)落在绿色部分(DB_TRX_ID<mid_id),表示这个版本是已提交的事务生成的,这个数据是可见的。
  2. 如果ROW的ID(DB_TRX_ID)落在红色部分(DB_TRX_ID>max_id),表示这个版本是由将来启动事务生成的,是肯定不可见的。
  3. 如果ROW的ID(DB_TRX_ID)落在黄色部分(mid_id<=DB_TRX_ID<=max_id),则分为两种情况:
    • DB_TRX_ID未提交的事务ID数组,表示这个版本是由还没有提交的事务生成的,不可见,当前自己的事物是可见的。
    • DB_TRX_ID不在未提交的事务ID数组,表示这个版本是已提交的事务生成的,可见。

对于删除的情况可以认为是update的特殊情况,会将版本链是最新的数据复制一份,然后将DB_TRX_ID修改成删除操作的DB_TRX_ID,同时在该条记录的头信息(record header)里(deleted flag)标记位写上ture,来表示当前记录已被删除,在查询时按照上而的规则查询到对应的记录如果deleted flag标记位为ture,意味着记录已被删除,则不返回数据。

例RR MVCC 判断流程

  1. user 表中存在一条用户信息,id:1 name:zxl.

  2. 首先#Transaction 100,#Transaction 200, #Transaction 300及#select同时开启事务。

  3. #Transaction 300更新name为zxl300并提交。

  4. #select进行查询操作,首次查询会创建ReadView,创建ReadView为[100,200],300,根据MVCC判断流程进行判断,当前记录链路DB_TRX_ID为300,300的区间应该在未提交及已提交范围,300不在未提交数组范围,所以本条记录是可见的,即返回zxl300.

  5. 而后#Transaction 100,进行了两次更新update user set name='zxl1' where id=1;update user set name='zxl2' where id=1;

  6. #select再次进行查询select name from user where id=1;,因为事务隔离级别为RR所以ReadView依然为[100,200],300,当前记录链路DB_TRX_ID为 100 ,100的区间应该在未提交及已提交范围,100在未提交数组范围,因此本条记录不可见,根据链路继续查询,发现还是100,则继续链路查询发现为300发现不在未提交范围内则返回zxl300

这篇关于MySQL MVCC机制深入的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1019669

相关文章

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

MySQL常用字符串函数示例和场景介绍

《MySQL常用字符串函数示例和场景介绍》MySQL提供了丰富的字符串函数帮助我们高效地对字符串进行处理、转换和分析,本文我将全面且深入地介绍MySQL常用的字符串函数,并结合具体示例和场景,帮你熟练... 目录一、字符串函数概述1.1 字符串函数的作用1.2 字符串函数分类二、字符串长度与统计函数2.1

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

Mysql中设计数据表的过程解析

《Mysql中设计数据表的过程解析》数据库约束通过NOTNULL、UNIQUE、DEFAULT、主键和外键等规则保障数据完整性,自动校验数据,减少人工错误,提升数据一致性和业务逻辑严谨性,本文介绍My... 目录1.引言2.NOT NULL——制定某列不可以存储NULL值2.UNIQUE——保证某一列的每一

解密SQL查询语句执行的过程

《解密SQL查询语句执行的过程》文章讲解了SQL语句的执行流程,涵盖解析、优化、执行三个核心阶段,并介绍执行计划查看方法EXPLAIN,同时提出性能优化技巧如合理使用索引、避免SELECT*、JOIN... 目录1. SQL语句的基本结构2. SQL语句的执行过程3. SQL语句的执行计划4. 常见的性能优

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

SQL Server 中的 WITH (NOLOCK) 示例详解

《SQLServer中的WITH(NOLOCK)示例详解》SQLServer中的WITH(NOLOCK)是一种表提示,等同于READUNCOMMITTED隔离级别,允许查询在不获取共享锁的情... 目录SQL Server 中的 WITH (NOLOCK) 详解一、WITH (NOLOCK) 的本质二、工作

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND