暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL的MVCC机制

卡布奇诺海晨 2025-06-04
170


MySQL 的 MVCC (Multi-Version Concurrency Control, 多版本并发控制) 是其核心存储引擎 InnoDB 实现高并发、非阻塞读的关键机制。它允许读操作不阻塞写操作,写操作也不阻塞读操作(在特定隔离级别下),从而极大地提升了数据库的并发性能。

以下是 MySQL InnoDB MVCC 的核心要点和工作原理:

  1. 核心思想:保留数据的历史版本

    • 当一行数据被修改时,InnoDB 不会立即覆盖原始数据,而是将原始数据标记为旧版本,并创建一个新版本。

    • 同时进行的读操作仍然可以访问到修改发生前的旧版本数据(快照)。

    • 数据的多个版本(旧版本)保存在 Undo Log 段中。

  2. 实现基础:隐藏字段
    InnoDB 在每一行记录(聚簇索引的叶子节点)中,除了用户定义的列,还添加了三个隐藏的系统字段:

    • DB_TRX_ID
       (6 Bytes): 记录最后一次修改(INSERT 或 UPDATE)该行记录的事务 ID

    • DB_ROLL_PTR
       (7 Bytes): 指向该行记录上一个版本在 Undo Log 中位置的指针(回滚指针)。利用这个指针可以构建一条该行记录的版本链

    • DB_ROW_ID
       (6 Bytes): 隐含的自增行 ID(Row ID)。如果表没有定义主键,InnoDB 会自动生成一个聚簇索引基于此字段。

  3. 关键组件:Undo Log

    • 事务回滚 (ROLLBACK
      ):通过 DB_ROLL_PTR
       找到旧版本数据并恢复。

    • 实现 MVCC:提供一致性读所需的历史快照。

    • UPDATE
      : 将修改前的行数据(包含所有字段)复制到 Undo Log 中,形成一个旧版本记录。然后更新当前行的数据,并将 DB_TRX_ID
       设置为当前事务 ID,DB_ROLL_PTR
       指向刚刚写入 Undo Log 的旧版本记录。

    • DELETE
      : InnoDB 实际上并不立即删除数据,而是将其标记为删除(设置一个删除标志)。同时,将删除前的整行数据复制到 Undo Log 中。真正的物理删除(Purge)由后台线程在确定没有任何事务需要访问这些旧版本数据时才进行。

    • 存储被修改数据的旧版本

    • 当进行 UPDATE
       或 DELETE
       操作时:

    • Undo Log 主要用于:

  4. 可见性判断:Read View

    • 如果 DB_TRX_ID
       在 trx_ids
       列表中,表示该事务当时活跃(未提交),则该版本不可见,继续找旧版本。

    • 如果 DB_TRX_ID
       不在 trx_ids
       列表中,表示该事务在生成 Read View 时已提交,则该版本可见

    • trx_ids
      : 生成 Read View 时,系统内所有活跃(已启动但未提交)的读写事务的事务 ID 列表。

    • low_limit_id
      : 生成 Read View 时,系统应该分配给下一个事务的 ID 值(即当前最大事务 ID + 1)。

    • up_limit_id
      : 活跃事务列表 trx_ids
       中最小的事务 ID。

    • creator_trx_id
      : 创建该 Read View 的事务自身的事务 ID(对于只读事务,该值为 0)。

    • 当一个事务(通常是只读事务或开启了 START TRANSACTION WITH CONSISTENT SNAPSHOT
      )执行普通的 SELECT
       查询(快照读)时,InnoDB 会为该事务生成一个 Read View(读视图)。

    • Read View 决定了该事务能看到数据的哪个版本。它包含以下关键信息:

    • 可见性规则:对于版本链中的每一行记录(通过 DB_ROLL_PTR
       回溯),使用该行的 DB_TRX_ID
       和当前事务的 Read View 进行判断:

    • 事务会沿着版本链(通过 DB_ROLL_PTR
      )依次应用这些规则,直到找到第一个对其可见的版本。

    1. 如果 DB_TRX_ID
       < up_limit_id
      :说明该版本是在生成 Read View 之前就已提交的事务修改的,可见

    2. 如果 DB_TRX_ID
       >= low_limit_id
      :说明该版本是在生成 Read View 之后才开启的事务修改的(或者就是本事务修改的但未提交),不可见。需要沿着版本链继续查找更旧的版本。

    3. 如果 up_limit_id
       <= DB_TRX_ID
       < low_limit_id
      :说明该版本是由在生成 Read View 时活跃的事务修改的。

    4. 如果 DB_TRX_ID
       = creator_trx_id
      :说明该版本是由本事务自己修改的,可见

  5. 与事务隔离级别的关系
    MVCC 主要在 READ COMMITTED (RC) 和 REPEATABLE READ (RR) 隔离级别下发挥核心作用。它们的主要区别在于 Read View 的生成时机

    • 在事务中第一次执行 SELECT
       语句(快照读)时
      生成一个 Read View。在整个事务期间,后续的所有快照读都复用这个第一次生成的 Read View

    • 因此,在同一个事务内,多次读取同一条记录,看到的是同一个历史快照(第一次读时的状态)。解决了脏读和不可重复读。

    • InnoDB 在 RR 级别下还通过 Next-Key Locking(间隙锁)机制来防止幻读(MVCC 的快照读本身不能完全防止幻读,因为新插入的数据可能不在快照中,但当前读会加锁阻止插入)。

    • 每次执行 SELECT
       语句(快照读)时,都会重新生成一个最新的 Read View。

    • 因此,它能读取到最新已提交的数据。解决了脏读,但可能出现不可重复读和幻读。

    • READ COMMITTED (RC)

    • REPEATABLE READ (RR)

  6. 快照读 vs. 当前读

    • SELECT ... FOR UPDATE

    • SELECT ... LOCK IN SHARE MODE

    • UPDATE
      DELETE
      INSERT

    • 读取的是数据的最新提交版本

    • 加锁(记录锁、间隙锁、Next-Key 锁)以保证操作的正确性和防止并发冲突。

    • 目的是处理当前最新的数据状态并进行修改。

    • 普通的 SELECT
       语句(不加 FOR UPDATE
       或 LOCK IN SHARE MODE
      )。

    • 使用 MVCC 机制,读取历史版本(Read View 决定),不加锁(理论上,可能遇到历史数据被 Purge 清理的情况,但通常不影响一致性)。

    • 目的是提供一致性的非锁定读。

    • 快照读 (Snapshot Read)

    • 当前读 (Current Read)

  7. Purge 操作

    • 随着事务的提交,不再需要访问的旧版本数据(Undo Log)会变得多余。

    • InnoDB 的后台线程 Purge Thread 会负责清理这些不再被任何 Read View 依赖的旧版本数据和 Undo Log 空间。这个过程称为 Purge。

    • 长事务会阻止 Purge 线程清理它可能需要的旧版本数据,导致 Undo Log 膨胀,这是需要注意的。

总结 MySQL InnoDB MVCC 的优势:

  • 高并发读: 读操作通常不需要加锁,不会被写操作阻塞。

  • 非阻塞写: 写操作通常只需要锁定当前处理的行(或间隙),不会阻塞其他行的读操作(快照读)。

  • 一致性读: 在不同隔离级别(RC/RR)下提供不同强度的一致性视图,避免脏读,解决不可重复读(RR)。

  • 高效回滚: Undo Log 天然支持事务回滚。

需要注意:

  • MVCC 主要在 READ COMMITTED 和 REPEATABLE READ 隔离级别下有效。READ UNCOMMITTED 总是读最新数据(可能脏读),SERIALIZABLE 会对所有读加锁,不使用 MVCC 的快照读。

  • MVCC 会增加存储开销(Undo Log 存储历史版本)和 CPU 开销(构建和遍历版本链)。

  • 理解 DB_TRX_ID
    DB_ROLL_PTR
    , Undo Log, Read View 以及可见性规则是掌握 MVCC 的关键。

通过 MVCC,MySQL InnoDB 在保证事务隔离性的同时,极大地提高了数据库的并发处理能力,是现代 OLTP 应用高性能的重要基石。

文章转载自卡布奇诺海晨,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论