04-MVCC

type
status
date
slug
summary
tags
category
icon
password
MySQL中的MVCC(Multi-Version Concurrency Control,多版本并发控制)InnoDB存储引擎实现高并发和事务隔离的核心机制,它依赖于Undo Log和隐藏列版本控制,避免了大量加锁导致的性能问题。

1️⃣ MVCC 工作原理

  • InnoDB 为每一行记录维护两个隐藏列
列名
说明
trx_id
最后一次修改该行的事务 ID
roll_pointer
指向 undo log 中的历史版本(旧值)地址
  • Undo Log(回滚日志) 当事务对记录进行 UPDATE / DELETE 时,InnoDB 会将旧版本写入 Undo Log,并通过 roll_pointer 链接旧数据版本,形成版本链

2️⃣ 快照读 vs 当前读

类型
使用方式
是否加锁
是否使用 MVCC
说明
快照读(Snapshot Read)
普通 SELECT
读取数据的历史版本
当前读(Current Read)
SELECT ... FOR UPDATE / UPDATE / DELETE
读取的是当前最新版本数据并加锁

3️⃣ MVCC 可见性判断规则

条件
描述
记录的trx_id < 当前事务id
说明这条记录是其他事务创建的
创建该版本的事务已经 提交
说明这条记录对当前事务可见
修改该版本的事务在当前事务启动后提交的
不可见(会通过 roll_pointer 继续向下找旧版本)

4️⃣ 不同隔离级别下 MVCC 的使用

隔离级别
使用 MVCC
行为说明
READ UNCOMMITTED
直接读最新数据,甚至未提交(脏读)
READ COMMITTED
每次读创建新的快照(不可重复读)
REPEATABLE READ(默认)
整个事务中快照固定(防止不可重复读)
SERIALIZABLE
所有读都加锁,MVCC 不使用

5️⃣ MVCC 局限与注意点

限制
说明
当前读不使用 MVCC
SELECT FOR UPDATE 必须加锁
DELETE/UPDATE 会生成新版本
并记录旧版本到 Undo Log
Undo Log 会增长
如果长事务不提交,会导致 Undo Log 积压
并不解决幻读
幻读通过 间隙锁(Gap Lock) 解决

6️⃣ Buffer Pool

Buffer PoolInnoDB 引擎的内存缓存区域,用于缓存以下类型的数据页:
类型
说明
数据页(Data Pages)
表记录页,最常用
索引页(Index Pages)
B+ 树结构的内部节点或叶子节点
Undo 页
回滚段中的页
插入缓冲页(Change Buffer)
二级索引的延迟更新页
系统页 / 字典页
系统表空间的元数据页
自适应哈希索引(AHI)
查询热点页动态构建的哈希索引
  • Buffer Pool 是由一组 页(Page) 组成,每页固定大小 16KB,可以设置 Buffer Pool 总容量(默认一个实例):
    组成部分
    说明
    LRU 链表
    最近最少使用(Least Recently Used)淘汰机制
    Free List
    空闲页,等待分配
    Flush List
    脏页列表,等待刷新到磁盘(刷盘)

    1.SQL 执行时的 Buffer Pool 交互机制

    • 🔁 读操作(SELECT)
      • 查询数据 → InnoDB 查看数据页是否在 Buffer Pool 中(称为 Buffer Pool 命中
      • 若命中,则直接从内存返回数据(快速)
      • 若未命中(Buffer Pool Miss):
        • 触发物理 IO,从磁盘加载页到 Buffer Pool
        • 若内存已满,则通过 LRU 淘汰冷数据页
        查询路径称为:逻辑读 → 物理读
    • 🔁 写操作(INSERT / UPDATE / DELETE)
      • 修改的数据页先在 Buffer Pool 中更新 → 页变为“脏页”
      • 同时写入 Undo Log(用于回滚)和 Redo Log(用于崩溃恢复)
      • 不立即写磁盘,后台线程异步刷新脏页(checkpoint)
      • ✅ 这是 WAL(Write-Ahead Logging)机制 的体现:先写日志,再写磁盘,保证事务一致性。

    2.Buffer Pool 的 LRU 淘汰策略(热数据优先)

    • 双端 LRU 链表:
      • [young区域] ←———→ [old区域] ↑ ↑ 最近使用 最久未用
      • 新加载页默认插入到 LRU 的中部(约 5/8 位置),防止全表扫描挤掉热点页
      • 热点页频繁访问将靠近头部,保留时间更长
    • 该策略可通过:
      • 控制全表扫描对缓存污染的影响。

    3.脏页刷盘机制(Checkpoint)

    Buffer Pool 中的脏页不能无限堆积,必须定期刷到磁盘:
    刷盘触发方式
    说明
    后台线程(默认)
    每秒/后台周期性写盘
    事务提交
    若启用 innodb_flush_log_at_trx_commit=1 则强制刷日志
    Redo Log 满了
    强制刷脏页释放空间
    Buffer Pool 满了
    淘汰页时需将脏页先写盘

    4.性能相关参数(重点)

    参数名
    描述
    innodb_buffer_pool_size
    ✅ 核心参数,设置 Buffer Pool 总容量,推荐为系统内存的 70%-80%(专用数据库)
    innodb_buffer_pool_instances
    Buffer Pool 分片个数,提升并发(建议 ≥ 1G 内存时设置为 2、4、8)
    innodb_flush_method
    控制刷盘方式,常见:O_DIRECT 避免双缓存
    innodb_flush_log_at_trx_commit
    控制日志刷新时机,影响事务安全性与性能
    innodb_lru_scan_depth
    LRU 每次扫描深度,影响淘汰效率
     
    上一篇
    03-事务隔离级别与锁机制
    下一篇
    01-数学
    Loading...