首页 > 数据库 >Mysql-Mvcc原理

Mysql-Mvcc原理

时间:2024-05-08 23:23:38浏览次数:38  
标签:事务 快照 读取 Mvcc trx Mysql 原理 数据 id

0.背景

在mysql的并发访问中,有几个典型的并发场景:

  • 读-读:无需处理,都是读取,不会对数据有影响。

  • 写-写:由于都涉及到数据的修改,不可能乱改,所以没有较好的方式来处理,一般都得加锁。

  • 读-写:读写场景,加锁当然ok。不过读操作是很频繁的,一但写数据就不让读取了,这种情况是让人很难受的。

    Mysql的前辈们通过Mvcc的方案来优化这个问题。通过Mvcc,可以无锁的方式兼顾读写的场景,无论数据是否在修改,都不会阻塞读操作。

1.快照读和当前读

mysql读取数据有当前读快照读的区分

数据嘛,无非就是增删改查,读取的时候,由于要考虑并发,可能会有别的事务在修改这个数据。

然后呢,Mysql引入了一个快照的概念,快照嘛,就跟照片一样,将一个临时的状态记录下来。

所以上面的2个呆板的词语,可以理解为:

  • 当前读:读取最新的数据
  • 快照读:读取快照时的数据

回到最开始的问题,写数据的时候,一定要阻塞吗?写数据的时候,可不可以读数据。

读数据,我不是读取最新的数据吗?我读取快照那个瞬间的数据有啥意思?

这个点在于我们处在当前事务的角度来看,事务的基本特性是ACID。

如果我们在一个事务里面,读取到的数据都是混乱的,那还能操作吗?

快照读的意义就是解决之前提到的不可重复读和幻读这些问题,来保证同一事务中的数据一致性。

关键点:是为了在当前事务中,保证数据读取的一致性。

1.1 当前读

对读取的记录加锁,读取最新的数据,并阻塞其他事务同时修改。

  • 读取的是数据库中当前的最新数据。
  • 如果其他事务正在对数据进行修改,在当前读中读取到的是已经提交的最新版本数据,而不考虑其他事务的未提交变更。
  • 在当前读中,事务读取数据时会获取短暂的共享锁,以确保其他事务在该事务读取数据期间不能修改数据,但不阻塞其他事务的读取操作。

场景:

-- 更新
-- 更新嘛,必须拿着最新的记录进行更新,不能拿个快照数据来更新,假设别的事务把数据给你删除了,还更新啊?
update ...

-- 删除
delete ...

-- 插入
insert ...

-- 共享锁
select ... lock in share mode

-- 独占锁
select ... for update

1.2 快照读

读数据不需要进行加锁,也不会阻塞和被其他事务阻塞。

  • 快照读是指事务在执行查询操作时,读取的是事务开始时的一致性快照,即查询操作在事务启动时所能看到的数据版本。
  • 快照读不会受到其他事务正在修改数据的影响,读取的是一致性的数据快照。
  • 在快照读中,事务读取数据时不会获取锁,因此不会阻塞其他事务的读取或写入操作。

场景:

-- 单纯的select操作(不包括上面的共享锁和独占锁)
select ...

2.Mvcc关键点

MVCC(Multi-version concurrency control 多版本并发控制)是一种并发控制机制,用于在事务并发执行时保证数据的一致性和隔离性,它就是快照读的一种解决方案。

2.1 隐藏字段

在Mysql中,事务id是默认递增的。

在数据库行记录中,存在一些隐藏字段,例如DB_TRX_IDDB_ROLL_PTRDB_ROW_ID等。

  • db_trx_id

    6-byte的事务ID,处理这条数据对应的事务id。

  • db_roll_ptr

    7-byte的回滚指针,就是指向行记录的上一个版本。

  • db_row_id

    6-byte的隐藏主键。如果数据表中没有主键,那么InnoDB会自动生成单调递增的隐藏主键(表中有主键或者非NULL的UNIQUE键时都不会包含 DB_ROW_ID列)。

DB_TRX_IDDB_ROLL_PTR这2个字段是Mvcc涉及到的主要字段。

image-20240507162752391

2.2 Undo Log(回滚日志)

在Mysql中进行数据修改时,会在undo log中记录存量的数据值,多个版本的数据进行记录后,就形成了一个版本链。

例如:回滚指针会指向上个版本的数据记录,例如在事务101、102中先后将name修改为了yang1和yang2。

image-20240507162812591

这个设计,方便实现以下功能。

  • 方便回滚,直接根据回滚指针找到之前的数据进行回退。
  • 在Mvcc中用于读取数据(后文描述)

2.3 Read View(读视图)

Read View(读视图)是进行查询操作时生成的一个视图,事务开始前会创建Read View(RC、RR级别有差异),根据生成的这个Read View,判断读取哪个版本的数据。

额,当做是个临时对象好了,存几个值方便后续进行比较。

包含4个关键字段

活跃事务:创建了事务但是还没提交

  • creator_trx_id:创建这个Read View的事务ID,即创建者的事务ID。
  • m_ids:创建ReadView时,活跃事务的ID集合。
  • min_trx_id:创建ReadView时,活跃事务中最小事务ID。
  • max_trx_id:创建ReadView时,当前最大事务ID+1(应该分配给下一个事务的id值)。

image-20240507173748434

这里要注意下min和max跟m_ids的关系:

1.min_trx_id是m_ids活跃事务集合中的最小值。

2.max_trx_id通常跟m_ids没关系,max_trx_id是在创建ReadView时,计划分配给下一个事务的ID值。

3.min_trx_id <= m_ids < max_trx_id

好,那我为啥要关注min_trx_id和max_trx_id呢?

ReadView记录了我们当前这瞬间的一些快照信息。

min_trx_id是快照时的最小活跃事务id,最小的活跃事务呀,如果一个事务id比这个min_trx_id小的话,这个事务在快照时就肯定被提交过了,相当于一个过去的事件,所以一定是可以看到的。

max_trx_id是快照时的待分配事务id,最大的事务id,如果一个事务id比这个max_trx_id还要大的话,这个事务快照时肯定还没提交,相当于一个未来的事件,那么肯定是不可见的。

2.3.1 RC和RR的差异

  • read committed (读已提交):事务每次select时都创建ReadView
  • repeatable read (可重复读):事务第一次select时创建ReadView,后续一直使用。

2.4 可见性判断

2.4.1 事务ID比较可见性

每个数据版本都有一个db_trx_id,代表创建该版本的事务ID(db_trx_id)。

db_trx_id与和ReadView中的参数进行比较,以确定该版本对当前事务的可见性。

2.4.2 可见性匹配原则

这里我的时间角度,就是说提交数据的那个事务(版本链中的事务),提交这个动作发生在什么时候

image-20240508231000827

首先,显而易见的几个条件是:

序号 条件 可见性 时间角度 描述
1 db_trx_id < min_trx_id 可见 过去 创建ReadView时,数据已经提交。
2 db_trx_id >= max_trx_id 不可见 未来 创建ReadView时,数据还位提交。
3 db_trx_id = creator_trx_id 可见 当前 就是当前事务,数据对当前事务可见。

对于min_trx_id <= db_trx_id < max_trx_id这个区间的数据,要结合m_ids来判断。

序号 条件 可见性 时间角度 描述
1 db_trx_idm_ids 不可见 未来 创建ReadView时,数据仍然活跃,还未提交。
2 db_trx_id 不在 m_ids 可见 过去 创建ReadView时,数据已经提交

2.4.3 判断检查结果

  • 如果数据版本对当前事务可见,则可以读取该数据版本。
  • 如果数据版本对当前事务不可见,则继续检查下一个版本,直到找到一个可见的版本或者版本链结束。

标签:事务,快照,读取,Mvcc,trx,Mysql,原理,数据,id
From: https://www.cnblogs.com/yang37/p/18181134

相关文章

  • 《编译原理》阅读笔记:p1-p3
    《编译原理》学习第1天,p1-p3总结,总计3页。一、技术总结1.compiler(编译器)p1,But,beforeaprogramcanberun,itfirstmustbetranslatedintoaforminwhichitcanbeexecutedbyacomputer.Thesoftwaresystemsthatdothistranslationarecalledcomp......
  • MySQL-09.性能分析工具的使用
    1.数据库服务器的优化步骤当遇到数据库调优问题时,思考的流程如下图。整个流程划分成了观察(Showstatus)和行动(Action)两个部分。字母S的部分代表观察(会使用相应的分析工具),字母A代表的部分是行动(对应分析可以采取的行动)。上图,就是数据库调优的思路。如果发现执行SQL时存......
  • MySQL索引创建原则
    1,2,5,6比较重要。针对于数据量较大,且查询比较频繁的表建立索引。单表超过10万数据(增加用户体验)。针对于常作为查询条件(where)、排序(orderby)、分组(groupby)操作的字段建立索引。尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。如果是字符......
  • mysql面试题
    索引失效1.模糊查询2.使用函数和计算:3.不匹配的数据类型:4.使用OR条件的不同索引列:5.复合索引的最左前缀原则:6.索引列在条件中使用负向查询:如NOTIN、NOTEXISTS、NOTLIKE等负向查询条件可能会导致索引失效。7.索引列在条件中使用NULL:当索引列中包含NULL值,并且在查询条件......
  • Mysql中的双路排序和单路排序
    在Mysql中使用orderby进行排序的时候,是可以使用到索引排序的,但是需要添加一些限制条件,例如:select*fromt_userwherename='张三'orderbyname;使用这种方式就可以使用到索引,同时使用limit也是可以使用到索引的select*fromt_userorderbyname;通过这种方式不会使用到索......
  • 线程池核心原理浅析
    前言由于系统资源是有限的,为了降低资源消耗,提高系统的性能和稳定性,引入了线程池对线程进行统一的管理和监控,本文将详细讲解线程池的使用、原理。为什么使用线程池池化思想线程池主要用到了池化思想,池化思想在计算机领域十分常见,主要用于减少资源浪费、提高性能等。池化思想......
  • 你知道什么是 MySQL Online DDL 吗?
    前言MySQL在进行DDL操作时,可能会产生表锁导致阻塞,影响用户的DML操作,而OnlineDDL指的是在DDL期间,允许用户进行DML操作。本文将详细讲解MySQL各版本的OnlineDDL。关于什么是DDL和DML操作,详细介绍见MySQL操作命令总结。1.什么是OnlineDDLOnlineDDL功......
  • 开关电源基本原理和相关概念
    开关电源作为现代电子设备中不可或缺的部分,为我们提供了高效稳定的电力解决方案。从家用电器到工业设备,从通信设备到计算机,开关电源在各种应用中发挥着关键作用。1工作原理开关电源利用开关器件(如MOSFET、BJT等)进行高速开关操作,通常采用脉冲宽度调制(PWM)技术去调整开关器件的工......
  • MySQL配置文件
    一.Linux1.MySQL5.7**MySQL5.7配置文件示例(适用于Linux)**[mysql]#设置mysql客户端默认字符集default-character-set=utf8[mysqld]#服务器端口port=3306#MySQL的安装目录basedir=/usr/local/mysql#MySQL的数据目录datadir=/var/lib/mysql#错误日志文件......
  • MySQL-安装脚本参考
    #!/bin/bash#安装MySQL程序install_mysql(){#mv/etc/yum.repos.d/*/tmp/#curl-o/etc/yum.repos.d/CentOS-Base.repohttps://mirrors.aliyun.com/repo/Centos-7.repo#wget-O/etc/yum.repos.d/epel.repohttp://mirrors.aliyun.com/repo/epel-7.repo#yuminstall-y......