MySQL MVCC原理深入探索

本文详细介绍了MySQL中MVCC(多版本并发控制)的工作原理,包括其由来、实际应用以及实现机制。在RR和RC隔离级别下,MVCC通过ReadView和UndoLog确保事务隔离性,提高并发查询性能。同时,讨论了MVCC对性能的影响以及RR级别下幻读问题的处理。MVCC通过非锁定读(快照读)和锁定读(当前读)策略,平衡了并发和一致性的需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

    • 一、MVCC的由来
    • 二、MVCC的实际应用
      • RR级别场景
      • RC级别场景
    • 三、MVCC的实现
      • 3.1 旧版本数据从哪里来——Undo Log
        • 3.1.1 插入操作对应的undo log
        • 3.1.2 删除操作对应的undo log
        • 3.1.3 更新操作对应的undo log
      • 3.2 多版本数据如何关联——行记录隐藏字段和版本链
      • 3.3 不同版本数据如何正确访问——Read View访问规则
        • 3.3.1 Read View
        • 3.3.2 覆盖索引下的MVCC
    • 四、扩展一——MVCC的多版本是否影响性能
    • 五、扩展二——RR级别能否完全避免幻读问题
    • 总结

一、MVCC的由来

我们知道:标准的数据库事务是要具备ACID特性的。但是对于【I】隔离性而言,可以根据不同的场景,权衡使用不同的隔离级别。在MySQL中实现了SQL标准中的四大隔离级别,同时对应了可能会出现的不同问题:

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED(读未提交) 可能 可能 可能
READ COMMITTED(读已提交) 不可能 可能 可能
REPEATABLE READ(可重复读) 不可能 不可能 *可能
SERIALIZABLE(可串行化) 不可能 不可能 不可能

其中,需要特别注意的一点是:也是与SQL标准规定不一样的一个地方,MySQL中RR可重复读的隔离级别下,是基本上不会出现幻读问题(这个地方会出现一些特殊的场景,后面会介绍)。

访问MySQL数据一般就是增删改查操作,对应的是insert、delete、update和select语句。

对于insert、delete、update这三种类型的语句而言,需要先定位到最新的数据;对于select语句,也有select … lock in share mode(MySQL8.0中增加了SELECT … FOR SHARE)/select… for update的操作,同样需要读取最新的数据,同时必须堵塞其他并发事务修改当前记录,所以需要进行加锁。 这些操作在MySQL中统一被称为——锁定读Locking Reads),又称为当前读。

而对于普通的select语句,MySQL则根据不同的隔离级别,进行不同的处理:

  • READ UNCOMMITTED(读未提交):读取最新的记录
  • READ COMMITTED(读已提交):读取最新提交事务的记录
  • REPEATABLE READ(可重复读):读取当前事务在开始前已提交的记录或者被自己事务修改的记录
  • SERIALIZABLE(可串行化):读取最新的记录,同时也加上读锁,事务提交前不允许被其他事务修改,也就是select … lock in share mode

可以看到,对于READ COMMITTED(读已提交)和 REPEATABLE READ(可重复读)这两种隔离级别来说,普通的select是不需要加锁的,并且受到事务发生时机的影响。可以利用事务保存的历史版本数据,控制版本访问权限,这种方案就称之为——MVCC(Multi-Version Concurrency Control),而MVCC下的select查询,被称为——非锁定读(Consistent Nonlocking Reads),又称为快照读。

生成的快照就被称之为ReadView(一致性视图)

利用MVCC提供的快照读能力,可以实现在不加锁的情况下,避免读写冲突时的堵塞问题,极大提升并发查询性能,同时也保证了事务的隔离性。这是在并发性能和数据一致性之间做的一次trade-off。


二、MVCC的实际应用

前面提到,MVCC是在RC和RR隔离级别下使用历史版本数据实现事务隔离性的,下面我们来看个具体的案例分析。

首先先创建表 t1:

CREATE TABLE `t1` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `c` (`c`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

#插入一条数据
INSERT INTO `t1` (
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeMavs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值