惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
爱范儿
爱范儿
H
Help Net Security
V
Visual Studio Blog
J
Java Code Geeks
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
MyScale Blog
MyScale Blog
The Cloudflare Blog
Martin Fowler
Martin Fowler
D
Docker
腾讯CDC
F
Fortinet All Blogs
雷峰网
雷峰网
GbyAI
GbyAI
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
博客园 - 聂微东
博客园 - 叶小钗

土法炼钢兴趣小组的算法知识备份

国密算法与国密 TLS 系列索引 【系统架构设计】架构质量属性:不只是"高可用高性能" 【系统架构设计百科】告警策略:如何避免"狼来了" 【系统架构设计】CQRS:读写分离的架构哲学 【系统架构设计】空间架构:极端扩展场景的解法 【系统架构设计】微服务架构深度审视:优势、代价与适用边界 【系统架构设计】扩展性原理:水平、垂直与对角扩展 【系统架构设计】无状态设计:扩展的第一步也是最难的一步 【系统架构设计】缓存架构:从本地到分布式的多级缓存体系 【系统架构设计】管道与过滤器:Unix 哲学的架构表达 【系统架构设计】复杂性管理:架构的核心战场 【系统架构设计】消息队列架构:异步解耦的设计与陷阱 【系统架构设计】CDN 架构:全球加速的设计原理 【系统架构设计】连接池设计:被忽视的性能杀手 【系统架构设计】弹性设计模式:熔断器、舱壁与超时 【系统架构设计】高可用设计模式:冗余、故障转移与仲裁 【系统架构设计】容量规划:从拍脑袋到数据驱动 【系统架构设计】数据库扩展:分库分表的工程实践与替代方案 【系统架构设计】SLO 工程:可靠性的量化管理 【系统架构设计】性能建模:用数学思维分析系统瓶颈 【系统架构设计】混沌工程:主动验证系统的韧性 【系统架构设计】零拷贝与内存映射:数据搬运的极致优化 【系统架构设计】线程模型:从 thread-per-request 到协程 【系统架构设计】容灾架构:多活与灾备设计 【系统架构设计】数据库性能模式:索引、查询与连接管理 【系统架构设计】数据建模:从关系范式到文档模型的真实权衡 【系统架构设计】吞吐量优化:批处理、流水线与并发模型 【系统架构设计】流处理架构:从批处理到实时的范式迁移 【系统架构设计】搜索引擎架构:倒排索引之上的系统设计 【系统架构设计】时序数据架构:监控与 IoT 的存储设计
【MySQL InnoDB 内核】B+Tree 与索引:聚簇、回表与页分裂
Liao Tonglang · 2026-06-18 · via 土法炼钢兴趣小组的算法知识备份

EXPLAIN 显示 Using index 时,优化器判断所需列均可从 同一二级索引 取得,InnoDB 无需再查聚簇索引——这是 覆盖索引(covering index)。若 Extra 仅有 Using wheretype=ref,往往意味着 回表(bookmark lookup):先在二级 B+Tree 上定位主键,再沿聚簇 B+Tree 读完整行。

InnoDB 是 index-organized table:用户数据只存在于 聚簇索引(clustered index) 的叶子页。这与 PostgreSQL 的 heap 表 + 独立 B-Tree 索引有根本差异。本文基于 MySQL 8.0.36 storage/innobase/btr/ 源码,追踪搜索、插入、分裂、合并的完整路径。


一、索引在存储栈中的位置

flowchart TD
  SQL[SQL DML/Query] --> OPT[Server Optimizer]
  OPT --> HAND[ha_innobase::index_read]
  HAND --> BTR[btr_cur_search_to_nth_level]
  BTR --> BUF[Buffer Pool buf_page_get]
  BUF --> PAGE[FIL_PAGE_INDEX 16KB]
  PAGE --> PD[Page Directory + 记录链表]
层级 关键文件 职责
Server sql/handler.h 优化器与存储引擎边界
Handler handler/ha_innodb.cc index_read, index_next, write_row
B+Tree btr/btr0btr.cc, btr/btr0cur.cc 树搜索、分裂、游标
Page page/page0page.cc, page/page0cur.cc 页内记录组织
Buffer buf/buf0buf.cc 页缓存、fix/unfix

第 02 篇 已说明 FIL 头、Infimum/Supremum、行格式;本篇聚焦 B+Tree 作为动态索引结构 的行为。

二、聚簇索引:主键即数据

InnoDB 表中 不存在 独立于索引的 heap 区。所有列(含隐藏列 DB_TRX_IDDB_ROLL_PTR)存储在聚簇索引叶节点。

2.1 聚簇索引的选择规则

  1. 显式 PRIMARY KEY
  2. 第一个 NOT NULL UNIQUE 索引
  3. 隐式 6 字节 DB_ROW_ID(无上述两者)

2.2 工程含义

现象 内核原因
范围扫描 PK 顺序 IO 友好 聚簇叶按 PK 物理有序
UUID 主键写入延迟尖刺 随机键 → 同一叶频繁 btr_page_split
更新 PK 行在聚簇树中 迁移,所有二级索引 entry 更新

2.3 非叶节点

非叶只存 索引键列 + 子页号(node pointer),不存非索引列——与经典 B+Tree 一致。

三、二级索引与回表

二级索引叶条目格式:(secondary_key_columns..., primary_key_columns...)

sequenceDiagram
  participant Q as SELECT col FROM t WHERE sec=?
  participant SI as Secondary B+Tree
  participant CI as Clustered B+Tree
  Q->>SI: btr_cur_search_to_nth_level
  SI-->>Q: PK values
  Q->>CI: 回表 search PK
  CI-->>Q: full row / MVCC version chain

覆盖索引SELECT 列 ⊆ 二级索引键 → EXPLAIN Extra=Using index

Change Buffer 只缓冲 二级索引 变更(目标叶不在 BP 时),聚簇变更不走 ibuf(第 15 篇)。

四、索引页布局与 Page Directory

flowchart TB
  FIL[FIL Header 38B] --> IH[Index Header]
  IH --> INF[Infimum 哨兵]
  INF --> USR[User Records 单向链表]
  USR --> SUP[Supremum 哨兵]
  SUP --> FREE[Free Space]
  FREE --> PD[Page Directory Slots]
  PD --> TR[FIL Trailer]

page0page.h 中 Index Header 字段:

字段 含义
PAGE_LEVEL 0=叶子
PAGE_N_RECS 用户记录数
PAGE_INDEX_ID 所属索引

Page Directory 在页尾提供稀疏槽位,page_cur_search_with_match() 先槽位二分再链表微调——页内查找近似 \(O(\log n)\)

FIL_PAGE_PREV / FIL_PAGE_NEXT 链接同层兄弟,支持 index_next() 顺序扫描而无需每次从根下降。

五、搜索路径 btr_cur_search_to_nth_level

btr/btr0cur.cc 中该函数是所有索引访问的核心:

level = root_level .. 0:
  block = buf_page_get(index, page_no)
  page_cur_search_with_match(block, tuple, mode)
  if level > 0:
    page_no = node pointer from record
  else:
    return btr_cur_t on leaf
page_cur_mode_t 语义
PAGE_CUR_LE ≤ key 的最大项
PAGE_CUR_GE ≥ key 的最小项
PAGE_CUR_G 严格大于 key

8.0 乐观搜索:无 latch 试读 → 失败则加 index latch 重试。

btr0pcur.ccpersistent cursor 保存 (modify_clock, block, rec_offset),供 index_next/index_prev 复用。

六、插入与页分裂

flowchart TD
  A[btr_cur_search 定位叶] --> B{btr_cur_optimistic_insert?}
  B -->|成功| C[page_cur_insert_rec + redo mtr]
  B -->|失败| D[btr_page_split 悲观分裂]
  D --> E[迁移半页 + 更新 FIL 兄弟链]
  E --> F[父节点插入 pointer 可能递归]
  F --> G[mtr_commit]
  C --> G

btr0btr.ccbtr_page_split() 步骤:

  1. fseg_alloc_free_page 分配新页
  2. page_copy_rec_list_end 迁移记录
  3. 更新 FIL_PAGE_PREV/NEXT
  4. 在父页插入 node pointer;父满则递归;根分裂则树高 +1

分裂期间持有 index tree latch(SMO 协议),同页并发插入阻塞——UUID PK 写入尖刺的常见根因。

所有修改经 mini-transaction 写 redo(第 04 篇)。

七、删除、合并与 purge

  • DELETE 通常设置 deleted mark,purge 线程异步物理删除(第 05 篇
  • 叶空间利用率过低时 btr_compress() 尝试与兄弟 合并
  • 合并触发远少于分裂

记录锁 / gap locklock0lock.cc 在定位叶后加锁(第 09 篇),与 B+Tree 结构 latch 分层。

八、并发:latch 层次

Latch 保护范围
Index SX/X 树结构变更(分裂/合并)
Block RW lock 单页记录
记录锁 逻辑键 / gap

读操作 RC 下一致性读走 MVCC(第 07 篇);SELECT ... FOR UPDATE当前读,在叶上加 X 记录锁。

九、覆盖索引、最左前缀与 ICP

-- 需本地验证
CREATE TABLE orders (
  id BIGINT PRIMARY KEY,
  user_id INT NOT NULL,
  status TINYINT,
  amount DECIMAL(10,2),
  KEY idx_user_status (user_id, status)
);
EXPLAIN SELECT user_id, status FROM orders WHERE user_id = 100;
-- 期望 Using index
  • 最左前缀(a,b,c) 索引可用于 aa,b 条件
  • ICP:Server 下推部分 WHERE 到 InnoDB 二级索引扫描(第 14 篇
  • MRR:批量回表前按 PK 排序,减少随机 IO

十、实验(需本地验证)

10.1 索引元数据

SELECT NAME, INDEX_ID, TYPE, N_FIELDS, PAGE_NO
FROM INFORMATION_SCHEMA.INNODB_INDEXES
WHERE TABLE_ID = (
  SELECT TABLE_ID FROM INFORMATION_SCHEMA.INNODB_TABLES
  WHERE NAME LIKE '%/orders'
);

10.2 对比随机 PK vs 递增 PK 写入

CREATE TABLE uuid_pk (id CHAR(36) PRIMARY KEY, pad VARCHAR(200)) ENGINE=InnoDB;
CREATE TABLE inc_pk (id BIGINT AUTO_INCREMENT PRIMARY KEY, pad VARCHAR(200)) ENGINE=InnoDB;
-- 同等行数 INSERT,对比 p99 延迟与 SHOW GLOBAL STATUS LIKE 'Innodb_data_pending%'

10.3 Buffer Pool 中索引页占比

SELECT page_type, COUNT(*) cnt
FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
GROUP BY page_type ORDER BY cnt DESC;

十一、PG 对照

维度 InnoDB PostgreSQL
数据组织 聚簇 B+Tree(IOT) Heap + B-Tree Index
页大小 16KB 8KB
页内布局 链表 + Page Directory ItemId + linp
兄弟链 FIL_PAGE_PREV/NEXT btpo_prev/next
纯索引扫描 覆盖二级索引 Index-Only Scan + VM

PG B-Tree 篇_bt_doinsert 分裂持 LWLock;InnoDB btr_page_split 持 index latch——故障形态类似(插入延迟尖刺),排查都需看 索引键顺序页分裂频率

十二、工程坑点与边界

坑点

  • 随机 UUID 主键导致分裂与碎片
  • 宽二级索引降低 BP 效率
  • PK 更新成本极高
  • 统计信息过期导致选错索引

边界

  • Change Buffer / AHI 见 第 15 篇
  • 空间索引 R-Tree 另走 gis/ 路径
  • 不讨论 MyISAM

十三、关键要点

  1. 聚簇索引即表;二级索引叶含 PK,非覆盖必回表。
  2. btr_cur_search_to_nth_level() 为搜索入口;Page Directory 页内二分。
  3. btr_page_split() 分裂持 latch;随机 PK 引发风暴。
  4. redo + mtr 保证分裂崩溃安全(第 10 篇)。
  5. 覆盖索引 避免回表;ICP/MRR 进一步优化计划。

十四、深度阅读清单

十四.1 btr_page_splitstorage/innobase/btr/btr0btr.cc

MySQL 8.0.36 中该函数负责:B+Tree 页分裂并维护父节点 pointer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.2 btr_cur_search_to_nth_levelstorage/innobase/btr/btr0cur.cc

MySQL 8.0.36 中该函数负责:自根至叶定位 cursor。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.3 page_cur_search_with_matchstorage/innobase/page/page0cur.cc

MySQL 8.0.36 中该函数负责:页内 Page Directory 二分查找。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.4 buf_page_get_genstorage/innobase/buf/buf0buf.cc

MySQL 8.0.36 中该函数负责:将 B+Tree 页读入 Buffer Pool。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.5 log_buffer_writestorage/innobase/log/log0log.cc

MySQL 8.0.36 中该函数负责:redo 写入 log buffer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.6 trx_commit_for_mysqlstorage/innobase/trx/trx0trx.cc

MySQL 8.0.36 中该函数负责:InnoDB 事务提交入口。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.7 lock_rec_lockstorage/innobase/lock/lock0lock.cc

MySQL 8.0.36 中该函数负责:在记录上加行锁或 gap lock。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.8 ibuf_insertstorage/innobase/ibuf/ibuf0ibuf.cc

MySQL 8.0.36 中该函数负责:Change Buffer 延迟二级索引写。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.9 btr_search_build_page_hash_indexstorage/innobase/btr/btr0sea.cc

MySQL 8.0.36 中该函数负责:为页构建 AHI hash。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.10 srv_mon_print_innodb_monitorstorage/innobase/srv/srv0mon.cc

MySQL 8.0.36 中该函数负责:输出 SHOW ENGINE INNODB STATUS。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.11 btr_page_splitstorage/innobase/btr/btr0btr.cc

MySQL 8.0.36 中该函数负责:B+Tree 页分裂并维护父节点 pointer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.12 btr_cur_search_to_nth_levelstorage/innobase/btr/btr0cur.cc

MySQL 8.0.36 中该函数负责:自根至叶定位 cursor。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.13 page_cur_search_with_matchstorage/innobase/page/page0cur.cc

MySQL 8.0.36 中该函数负责:页内 Page Directory 二分查找。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.14 buf_page_get_genstorage/innobase/buf/buf0buf.cc

MySQL 8.0.36 中该函数负责:将 B+Tree 页读入 Buffer Pool。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.15 log_buffer_writestorage/innobase/log/log0log.cc

MySQL 8.0.36 中该函数负责:redo 写入 log buffer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.16 trx_commit_for_mysqlstorage/innobase/trx/trx0trx.cc

MySQL 8.0.36 中该函数负责:InnoDB 事务提交入口。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.17 lock_rec_lockstorage/innobase/lock/lock0lock.cc

MySQL 8.0.36 中该函数负责:在记录上加行锁或 gap lock。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.18 ibuf_insertstorage/innobase/ibuf/ibuf0ibuf.cc

MySQL 8.0.36 中该函数负责:Change Buffer 延迟二级索引写。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.19 btr_search_build_page_hash_indexstorage/innobase/btr/btr0sea.cc

MySQL 8.0.36 中该函数负责:为页构建 AHI hash。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.20 srv_mon_print_innodb_monitorstorage/innobase/srv/srv0mon.cc

MySQL 8.0.36 中该函数负责:输出 SHOW ENGINE INNODB STATUS。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.21 btr_page_splitstorage/innobase/btr/btr0btr.cc

MySQL 8.0.36 中该函数负责:B+Tree 页分裂并维护父节点 pointer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.22 btr_cur_search_to_nth_levelstorage/innobase/btr/btr0cur.cc

MySQL 8.0.36 中该函数负责:自根至叶定位 cursor。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.23 page_cur_search_with_matchstorage/innobase/page/page0cur.cc

MySQL 8.0.36 中该函数负责:页内 Page Directory 二分查找。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.24 buf_page_get_genstorage/innobase/buf/buf0buf.cc

MySQL 8.0.36 中该函数负责:将 B+Tree 页读入 Buffer Pool。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.25 log_buffer_writestorage/innobase/log/log0log.cc

MySQL 8.0.36 中该函数负责:redo 写入 log buffer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.26 trx_commit_for_mysqlstorage/innobase/trx/trx0trx.cc

MySQL 8.0.36 中该函数负责:InnoDB 事务提交入口。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.27 lock_rec_lockstorage/innobase/lock/lock0lock.cc

MySQL 8.0.36 中该函数负责:在记录上加行锁或 gap lock。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.28 ibuf_insertstorage/innobase/ibuf/ibuf0ibuf.cc

MySQL 8.0.36 中该函数负责:Change Buffer 延迟二级索引写。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.29 btr_search_build_page_hash_indexstorage/innobase/btr/btr0sea.cc

MySQL 8.0.36 中该函数负责:为页构建 AHI hash。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.30 srv_mon_print_innodb_monitorstorage/innobase/srv/srv0mon.cc

MySQL 8.0.36 中该函数负责:输出 SHOW ENGINE INNODB STATUS。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.31 btr_page_splitstorage/innobase/btr/btr0btr.cc

MySQL 8.0.36 中该函数负责:B+Tree 页分裂并维护父节点 pointer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.32 btr_cur_search_to_nth_levelstorage/innobase/btr/btr0cur.cc

MySQL 8.0.36 中该函数负责:自根至叶定位 cursor。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.33 page_cur_search_with_matchstorage/innobase/page/page0cur.cc

MySQL 8.0.36 中该函数负责:页内 Page Directory 二分查找。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.34 buf_page_get_genstorage/innobase/buf/buf0buf.cc

MySQL 8.0.36 中该函数负责:将 B+Tree 页读入 Buffer Pool。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.35 log_buffer_writestorage/innobase/log/log0log.cc

MySQL 8.0.36 中该函数负责:redo 写入 log buffer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.36 trx_commit_for_mysqlstorage/innobase/trx/trx0trx.cc

MySQL 8.0.36 中该函数负责:InnoDB 事务提交入口。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.37 lock_rec_lockstorage/innobase/lock/lock0lock.cc

MySQL 8.0.36 中该函数负责:在记录上加行锁或 gap lock。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.38 ibuf_insertstorage/innobase/ibuf/ibuf0ibuf.cc

MySQL 8.0.36 中该函数负责:Change Buffer 延迟二级索引写。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.39 btr_search_build_page_hash_indexstorage/innobase/btr/btr0sea.cc

MySQL 8.0.36 中该函数负责:为页构建 AHI hash。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.40 srv_mon_print_innodb_monitorstorage/innobase/srv/srv0mon.cc

MySQL 8.0.36 中该函数负责:输出 SHOW ENGINE INNODB STATUS。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.41 btr_page_splitstorage/innobase/btr/btr0btr.cc

MySQL 8.0.36 中该函数负责:B+Tree 页分裂并维护父节点 pointer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.42 btr_cur_search_to_nth_levelstorage/innobase/btr/btr0cur.cc

MySQL 8.0.36 中该函数负责:自根至叶定位 cursor。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.43 page_cur_search_with_matchstorage/innobase/page/page0cur.cc

MySQL 8.0.36 中该函数负责:页内 Page Directory 二分查找。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.44 buf_page_get_genstorage/innobase/buf/buf0buf.cc

MySQL 8.0.36 中该函数负责:将 B+Tree 页读入 Buffer Pool。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.45 log_buffer_writestorage/innobase/log/log0log.cc

MySQL 8.0.36 中该函数负责:redo 写入 log buffer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.46 trx_commit_for_mysqlstorage/innobase/trx/trx0trx.cc

MySQL 8.0.36 中该函数负责:InnoDB 事务提交入口。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.47 lock_rec_lockstorage/innobase/lock/lock0lock.cc

MySQL 8.0.36 中该函数负责:在记录上加行锁或 gap lock。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.48 ibuf_insertstorage/innobase/ibuf/ibuf0ibuf.cc

MySQL 8.0.36 中该函数负责:Change Buffer 延迟二级索引写。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.49 btr_search_build_page_hash_indexstorage/innobase/btr/btr0sea.cc

MySQL 8.0.36 中该函数负责:为页构建 AHI hash。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.50 srv_mon_print_innodb_monitorstorage/innobase/srv/srv0mon.cc

MySQL 8.0.36 中该函数负责:输出 SHOW ENGINE INNODB STATUS。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.51 btr_page_splitstorage/innobase/btr/btr0btr.cc

MySQL 8.0.36 中该函数负责:B+Tree 页分裂并维护父节点 pointer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.52 btr_cur_search_to_nth_levelstorage/innobase/btr/btr0cur.cc

MySQL 8.0.36 中该函数负责:自根至叶定位 cursor。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.53 page_cur_search_with_matchstorage/innobase/page/page0cur.cc

MySQL 8.0.36 中该函数负责:页内 Page Directory 二分查找。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.54 buf_page_get_genstorage/innobase/buf/buf0buf.cc

MySQL 8.0.36 中该函数负责:将 B+Tree 页读入 Buffer Pool。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.55 log_buffer_writestorage/innobase/log/log0log.cc

MySQL 8.0.36 中该函数负责:redo 写入 log buffer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.56 trx_commit_for_mysqlstorage/innobase/trx/trx0trx.cc

MySQL 8.0.36 中该函数负责:InnoDB 事务提交入口。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.57 lock_rec_lockstorage/innobase/lock/lock0lock.cc

MySQL 8.0.36 中该函数负责:在记录上加行锁或 gap lock。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.58 ibuf_insertstorage/innobase/ibuf/ibuf0ibuf.cc

MySQL 8.0.36 中该函数负责:Change Buffer 延迟二级索引写。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.59 btr_search_build_page_hash_indexstorage/innobase/btr/btr0sea.cc

MySQL 8.0.36 中该函数负责:为页构建 AHI hash。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.60 srv_mon_print_innodb_monitorstorage/innobase/srv/srv0mon.cc

MySQL 8.0.36 中该函数负责:输出 SHOW ENGINE INNODB STATUS。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.61 btr_page_splitstorage/innobase/btr/btr0btr.cc

MySQL 8.0.36 中该函数负责:B+Tree 页分裂并维护父节点 pointer。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.62 btr_cur_search_to_nth_levelstorage/innobase/btr/btr0cur.cc

MySQL 8.0.36 中该函数负责:自根至叶定位 cursor。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

十四.63 page_cur_search_with_matchstorage/innobase/page/page0cur.cc

MySQL 8.0.36 中该函数负责:页内 Page Directory 二分查找。

步骤 动作
1 在 tag mysql-8.0.36 下打开源文件
2 自函数入口向下读 80–120 行
3 记录 mtr_start / mtr_commit 边界
4 对照调用方是否需要 index latch

上一篇崩溃恢复

下一篇Binlog 与两阶段提交

参考资料

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-06-18 · database / kernel

【MySQL InnoDB 内核】InnoDB 存储引擎机制深度拆解

从线程模型到页格式、从 undo log MVCC 到 binlog 两阶段提交——对 MySQL InnoDB 做源码级拆解,并与 PostgreSQL 内核系列逐章对照。20 篇覆盖内核机制与生产运维实战,面向 MySQL DBA、从 PG 转 MySQL 的后端与数据库内核开发者。