深入揭秘:MySQL中MVCC的神奇原理

2024年 7月 8日 35.4k 0

要解决读一致性的问题,保证一个事务中前后两次读取数据结果一致,还有一种 MVCC 的方式,又叫多版本的并发控制(Multi Version Concurrency Control)。

MVCC 就是为了让一个事务前后两次读取到的数据保持一致,在修改数据的时候给它建立一个快照,后面的查询操作读取这个快照就可以了。MVCC 解决了加上排他锁后的行记录,可以被查询到的问题,从而解决了由于写操作阻塞而引发读操作并发的问题。

InnoDB 为每一行记录都默认生成两个隐藏列:DATA_TRX_ID 、 DATA_ROLL_PTR 。

DATA_TRX_ID,记录最新插入或者更新这条行记录的事务 ID ,大小为 6 个字节,事务编号是自动递增的(我们把它理解为创建版本号,在数据新增或者修改为新数据的时候,记录当前事务 ID)。

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

1

MVCC 的原理讲解

深入揭秘:MySQL中MVCC的神奇原理-1

第一个事务:

    begin; 
    insert into person values(1,'张三'); 
    insert into person values(2,'李四'); 
    commit;

    此时的数据,创建版本是当前事务ID,删除版本为空,如下表:

    深入揭秘:MySQL中MVCC的神奇原理-2

    第二个事务:执行第 1 次查询,读取到两条原始数据,是“张三”和“李四”两个数据,这个时候事务 ID 是 2,

      select * from person;

      第三个事务,插入数据:

        begin;
        insert into person values(3,'王五');
        commit;

        此时的数据,多了一条“王五”,它的创建版本号是当前事务编号 3,如下表:

        深入揭秘:MySQL中MVCC的神奇原理-3

        第二个事务,执行第 2 次查询:

          select * from person;

          MVCC 的查找规则:只能查找创建时间小于等于当前事务 ID 的行,和删除时间大于当前事务 ID 的行(或者回滚版本为空的行)。

          因此以上的过程不能查到第三个事务插入的数据“王五”,“王五”的创建版本号为 3 大于第二个事务的 ID 2,所以还是只能查到创建版本号为 1 的两条数据,即“张三”和“李四”两个数据。

          第四个事务,删除数据,删除了 id = 2 的“李四”的这条记录,

            begin;
            delete from mvcctest where id = 2;
            commit;

             此时的数据,“李四”的回滚版本号被记录为当前事务 ID 4,其他数据不变,如下表:

            深入揭秘:MySQL中MVCC的神奇原理-4

            在第二个事务中,执行第 3 次查询:

              select * from person;

              MVCC 的查找规则:只能查找创建时间小于等于当前事务 ID 的行,和删除时间大于当前事务 ID 的行(或者回滚版本为空的行)。

              因此以上的过程能查到第四个事务删除的数据“王五”,“王五”的回滚版本号 为 4 大于第二个事务的 ID 2,所以还是只能查到创建版本号为 1 的数据和回滚版本号为 4 的数据,还是“张三”和“李四”两个数据。

              第五个事务,执行更新操作,这个事务 ID是5,

                begin; 
                update person set name = '赵六' where id = 1;
                commit;

                此时的数据,第五个事务更新“张三”数据的时候,旧数据的回滚版本号被记录为当前事务ID 5(同时写入 undo 日志),产生了一条新数据,创建版本号为当前事务ID 5,如下表:

                深入揭秘:MySQL中MVCC的神奇原理-5

                第二个事务,执行第 4 次查询,

                  select * from person;

                  MVCC 的查找规则:只能查找创建时间小于等于当前事务 ID 的行,和删除时间大于当前事务 ID 的行(或者回滚版本为空的行)。

                  因此以上的过程不能查到第三个事务插入的数据“王五”,“王五”的创建版本号为 3 大于第二个事务的 ID 2,所以还是只能查到创建版本号为 1 的两条数据,即“张三”和“李四”两个数据。

                  第五个事务更新后的数据"赵六"的创建版本号大于 2,代表是在第二个事务之后增加的,查不出来,而旧数据“张三”的回滚版本号大于 2,代表是在第二个事务之后删除的,可以查出来。所以还是只能查到创建版本号为 1 的两条数据,即“张三”和“李四”两个数据。

                  通过以上 MVCC 的讲解,我们能看到,通过创建版本号与回滚版本号的查找规则,无论其他事务是插入、修改、或者删除,第二个事务查询到的数据都没有变化,从而说明 MVCC 解决了读一致性的问题。

                  需要说明的是,以上的例子是基于第二个事务是查询操作,如果查询操作在插入、修改、或者删除之后,同时这些操作没有提交的情况下,那么按照 MVCC 的查找规则,查询的事务还是不能保证的一致性。

                  在 InnoDB 存储引擎中,MVCC 是通过 MVCC 的查找规则 结合  Undo Log 一起实现的读一致性。

                  2

                  理解 Undo Log、Redo Log 的作用

                  深入揭秘:MySQL中MVCC的神奇原理-1

                  1、了解 Undo Log

                  Undo Log 是为了实现事务的原子性产生的,在事务开始之前,在对数据进行操作之前,首先需要把操作的数据备份到一个日志文件里,以便在事务处理过程中出现异常或者回退时,MySQL 可以利用 Undo Log 中的备份数据恢复到事务执行前的状态,主要是用于回滚操作。

                  上面提到的 MVCC 是通过 MVCC 的查找规则 结合  Undo Log 一起实现的读一致性的根本原因在于 Undo  Log 保存了未提交之前的老版本数据,因此可以将其作为老版本快照便于其他事务来进行并发的读操作。

                  快照读:普通的 select 查询就是快照读,它是由缓存区(Undo buffer)和 undo 区(Undo Log)两部分组成。

                  当前读:sql 读取的是最新版本的数据,加锁的数据读取都是当前读。

                  2、了解 Redo Log

                  Redo Log 是为了实现恢复操作产生的,是为了实现事务的持久性。Redo Log 把事务中操作的任何数据,都把最新的数据备份到一个日志文件里,它不是事务提交后才写入日志文件,而是在事务的执行过程中就开始写入 Redo Log。

                  Redo Log 实现事务的持久性是指在发生故障的时候,如果有脏页没有写入磁盘,在重启 MySQL 服务的时候,根据 Redo Log 进行重做,从而把没有写入磁盘数据进行持久化的操作。

                  深入揭秘:MySQL中MVCC的神奇原理-6

                  后面将为大家介绍 SQL 语句调优 explain 的用法。

                  相关文章

                  Oracle如何使用授予和撤销权限的语法和示例
                  Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
                  下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
                  社区版oceanbase安装
                  Oracle 导出CSV工具-sqluldr2
                  ETL数据集成丨快速将MySQL数据迁移至Doris数据库

                  发布评论