Bootstrap

【MySQL】InooDB存储引擎与MVCC实现原理

InnoDB 的 Redo Log、Undo Log 和 MVCC 详解


0.InnoDB存储引擎架构

InnoDB 是 MySQL 的默认存储引擎,具有高可靠性和性能,支持事务和行级锁。

(1)InnoDB架构核心组件

  • Buffer Pool(缓冲池):
    • 用于缓存表数据和索引,减少磁盘 I/O 操作。
    • 包含数据页、索引页、插入缓冲等。
  • Redo Log(重做日志):
    • 记录事务操作,用于崩溃恢复。
    • 提供 WAL(Write-Ahead Logging)机制,确保日志先写磁盘再修改数据。
  • Undo Log(回滚日志):
    • 用于事务回滚和 MVCC 的实现。
    • 每个事务的更新会记录到 Undo Log。
  • Adaptive Hash Index(自适应哈希索引):
    • 自动生成的哈希索引,提高某些查询的速度。
  • Change Buffer(变更缓冲区):
    • 暂存对非唯一索引的修改,异步写入磁盘。
    • 提高批量写入性能。
  • Doublewrite Buffer(双写缓冲):
    • 防止单页写入损坏数据,通过两次写操作保障一致性。

2. 事务原理

(1)ACID特性

InnoDB 通过以下机制实现 ACID:

  • 原子性(Atomicity): 通过 Undo Log 回滚未完成的事务。
  • 一致性(Consistency): 数据在事务之间保持一致。
  • 隔离性(Isolation): 支持 4 种隔离级别,防止事务间干扰。
  • 持久性(Durability): 使用 Redo Log 保证事务提交后的数据持久化。

(2)事务隔离级别

  • READ UNCOMMITTED(未提交读):
    • 允许读取未提交的数据,可能出现脏读。
  • READ COMMITTED(提交读):
    • 只能读取已提交的数据,防止脏读。
  • REPEATABLE READ(可重复读):
    • 同一事务内多次读取结果一致,防止幻读和不可重复读。
  • SERIALIZABLE(可串行化):
    • 最高隔离级别,所有事务按顺序执行,防止一切并发问题。

(3)锁机制

InnoDB 提供以下锁:

  • 行级锁:
    • Record Lock(记录锁): 锁定行记录本身。
    • Gap Lock(间隙锁): 锁定索引间隙,防止幻读。
    • Next-Key Lock(临键锁): 记录锁 + 间隙锁。
  • 意向锁:
    • 意向共享锁(IS): 表示事务想对某些行加共享锁。
    • 意向排他锁(IX): 表示事务想对某些行加排他锁。

1. 什么是 MVCC?

MVCC(多版本并发控制,Multi-Version Concurrency Control)是一种实现高效并发的机制。
通过维护数据的多个版本,避免了读操作加锁,从而提升数据库性能。
MVCC 是事务隔离实现的关键,特别适用于读多写少的场景(如 OLTP 系统)。


2. MVCC 的核心组件

组件描述
隐藏列InnoDB 每行数据都包含两个隐藏列:
- DB_TRX_ID:记录最后一次修改该行的事务 ID。
- DB_ROLL_PTR:指向 Undo Log 的指针,用于存储历史版本数据。
Undo Log- 记录每次更新操作前的旧版本数据(逻辑日志)。
- 提供快照数据供快照读(Snapshot Read)使用。
Read View- 每个事务启动时创建的视图,记录当前活跃事务和其版本信息。
- 决定事务可以看到哪些版本的数据。

3. 两种读操作:快照读与当前读

(1)快照读(Snapshot Read)

  • 定义: 通过 MVCC 机制读取历史版本数据,而不是直接读取当前数据。
  • 特点: 不加锁,性能高。
  • 适用场景: 普通 SELECT 语句,例如:
    SELECT * FROM products WHERE stock > 0;
    

(2)当前读(Current Read)

  • 定义: 读取最新数据,并加锁防止其他事务修改。
  • 特点: 需要加锁,性能较低。
  • 适用场景: 修改或加锁读取,例如:
    SELECT * FROM products WHERE id = 1 FOR UPDATE;
    UPDATE products SET stock = stock - 1 WHERE id = 1;
    

4. MVCC 的实现原理

(1)隐藏列与版本控制

  • 每行记录都包含两个隐藏列:
    • DB_TRX_ID:记录最后一次修改该行的事务 ID。
    • DB_ROLL_PTR:指向 Undo Log,用于找到之前版本的快照数据。

(2)Undo Log 提供快照

  • Undo Log 保存每次更新前的数据版本。
  • 快照读时,通过 DB_ROLL_PTR 指针找到 Undo Log,返回快照数据。

(3)Read View 决定可见性

  • Read View 内容:

    • 当前活跃事务列表: 包含事务启动时所有尚未提交的事务 ID。
    • 最小活跃事务 ID(min_trx_id): 活跃事务中最早的事务 ID。
    • 下一个分配事务 ID(max_trx_id): 尚未分配的事务 ID。
  • 数据版本可见性判断规则:

    1. 如果 DB_TRX_ID 小于 min_trx_id,表示该版本在事务启动前已提交,对当前事务可见。
    2. 如果 DB_TRX_ID 大于等于 max_trx_id,表示该版本在事务启动后生成,对当前事务不可见。
    3. 如果 DB_TRX_ID 在活跃事务列表中,表示该版本尚未提交,对当前事务不可见。

(4)隔离级别对快照的影响

  • READ COMMITTED: 每次查询生成新的 Read View,读取最新快照数据。
  • REPEATABLE READ: 同一事务内的查询使用固定的 Read View,保证多次读取结果一致。

5. Redo Log 和持久性

特性描述
主要作用保证事务的持久性(Durability),即提交的事务数据即使系统崩溃也不会丢失。
工作原理- Redo Log 是物理日志,记录数据页的更改。
- 修改先写入 Redo Log,之后再将数据异步刷新到磁盘。
WAL机制Write-Ahead Logging:先写日志,再写数据。
崩溃恢复在数据库重启时,Redo Log 用于重做已提交但未写入磁盘的数据,保证数据一致性。
优化参数- innodb_log_file_size:控制日志文件大小。
- innodb_flush_log_at_trx_commit:控制刷新策略。
流程图事务更新 -> 写入 Redo Log -> 提交 -> 异步刷新到数据文件。

6. Undo Log 和原子性

特性描述
主要作用保证事务的原子性(Atomicity),即未完成的事务可以被完全回滚,确保事务操作要么全部完成,要么全部撤销。
工作原理- Undo Log 是逻辑日志,记录数据行的修改前值。
- 回滚操作依赖 Undo Log 恢复数据到修改前的状态。
事务回滚如果事务失败或主动回滚,Undo Log 逐步撤销事务的所有更改。
MVCC的支持Undo Log 提供之前版本的快照数据,支持 MVCC 实现多版本并发控制。
日志类型每次更新生成 Undo Log,写入 DB_ROLL_PTR 指向的 Undo 日志链表。
流程图事务更新 -> 写入 Undo Log -> 提交或回滚时使用 Undo Log 还原数据。

7. 数据可见性判断示例

假设:

  • 当前事务 ID:10。
  • 活跃事务列表:[8, 9]。
  • 数据行的 DB_TRX_ID 和 Undo Log 如下:
版本号(DB_TRX_ID)数据内容事务状态
15stock = 50尚未提交,不可见
9stock = 60活跃事务,不可见
7stock = 70已提交,可见

判断规则:

  • 版本 15 的事务未提交,不可见。
  • 版本 9 的事务是活跃事务,不可见。
  • 版本 7 的事务已提交且早于当前事务启动,可见。

最终结果:stock = 70


8. 三者关系总结

组件作用实现机制与其他组件的关系
Redo Log保证事务持久性(D)WAL机制:先写日志,再写数据配合事务提交确保数据持久化;与 Undo Log 无直接关联。
Undo Log保证事务原子性(A);支持 MVCC记录修改前的旧值,回滚时使用;提供快照数据支持 MVCC支持 MVCC 的快照读;在回滚时恢复修改前数据;回滚时无需 Redo Log。
MVCC支持高并发读写(隔离性 I)依赖 Undo Log 提供历史版本,结合 Read View 实现一致性快照读。依赖 Undo Log 记录旧版本数据;Redo Log 不直接参与 MVCC 的实现。
;