MySQL 8.0Notes

第 01 章:源码全景

zjc 于 2026-01-01 发布

这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 MySQL 8.0 源码庞大,但它有清晰的模块边界。读源码的第一步不是逐行阅读,而是建立地图:连接如何进入 Server 层,SQL 如何解析和优化,执行器如何调用存储引擎,InnoDB 如何管理页面、事务、锁和日志。

本章目标是建立 MySQL 8.0 源码阅读的全局视角。

1.1 为什么要读源码

读源码能解决文档没有覆盖的问题:

  1. 理解执行计划为什么这样选;
  2. 理解锁范围为什么比预期大;
  3. 理解参数默认值背后的机制;
  4. 理解错误日志和状态指标来源;
  5. 判断性能问题在 SQL 层还是引擎层;
  6. 验证社区博客结论是否适用当前版本;
  7. 为内核修改和深度排障打基础。

读源码不是为了背代码行数,而是为了建立可验证的机制模型。

1.2 源码目录概览

以 MySQL 8.0 社区源码为例,常见目录:

目录 职责
sql/ SQL 层核心、解析、优化、执行、协议
storage/innobase/ InnoDB 存储引擎
include/ 公共头文件
mysys/ 系统库封装
libbinlogevents/ Binlog 事件定义
client/ 客户端工具
router/ MySQL Router
plugin/ 插件
unittest/ 单元测试
mysql-test/ MTR 测试
cmake/ 构建配置

最重要的两个目录:

sql/
  -> Server layer

storage/innobase/
  -> InnoDB

1.3 一条 SQL 的调用链

查询的大致路径:

mysql_real_query / COM_QUERY
  -> dispatch_command
     -> mysql_parse
        -> parse_tree
           -> mysql_execute_command
              -> open_tables
              -> optimize
              -> execute
                 -> handler interface
                    -> ha_innobase
                       -> row_search / row_insert / row_update

写入语句还涉及:

Server层
  -> binlog prepare
  -> engine prepare
  -> binlog write
  -> engine commit

这就是 redo log 和 binlog 的两阶段提交路径。

1.4 SQL 层核心模块

模块 主要职责
Connection Handler 管理客户端连接和线程
Protocol 编解码 MySQL 协议包
Parser 语法解析
Resolver 语义解析、表和列解析
Transformer 逻辑改写
Optimizer 代价估算、连接顺序、访问方法
Executor 执行迭代器
Table Cache 表定义缓存
Lock Manager Server 层元数据锁
Binlog 逻辑日志

MySQL 8.0 优化器和执行器相比 5.6/5.7 有明显重构,例如基于迭代器的执行模型和新优化器结构。

1.5 InnoDB 核心模块

模块 职责
fil 文件空间管理
buf Buffer Pool
btr B+Tree
row 行操作
rem 记录管理
lock 锁系统
trx 事务
undo 回滚段和版本链
log redo log
mtr mini transaction
page 页面管理
ibuf Change Buffer
purge 清理 delete mark
dict 数据字典缓存
fts 全文索引

推荐阅读顺序:

buf -> page -> btr -> row -> trx -> lock -> undo -> log -> purge

先懂页面和索引,再懂事务和锁,最后读恢复和后台线程。

1.6 编译与调试准备

获取源码:

git clone https://github.com/mysql/mysql-server.git
cd mysql-server
git checkout mysql-8.0.xx

常见依赖:

sudo apt install build-essential cmake ninja-build \
  libssl-dev libncurses-dev libtirpc-dev \
  bison pkg-config

构建:

mkdir build
cd build
cmake .. -GNinja \
  -DCMAKE_BUILD_TYPE=Debug \
  -DWITH_UNIT_TESTS=OFF \
  -DWITH_DEBUG=ON
ninja

启动调试:

./runtime_output_directory/mysqld --defaults-file=my.cnf --user=mysql

调试建议:

  1. 使用 Debug 构建;
  2. 固定小数据集;
  3. 用 MTR 复现;
  4. 在 SQL 层入口和 handler 接口断点;
  5. 结合 EXPLAIN FORMAT=TREE
  6. 结合 performance_schema;
  7. 阅读对应测试用例。

1.7 源码阅读方法

推荐方法:

  1. 先写可复现实验;
  2. 再看执行计划;
  3. 根据现象猜测模块;
  4. 从入口函数进入;
  5. 画调用链;
  6. 记录关键结构体;
  7. 用断点验证;
  8. 对照测试;
  9. 输出笔记。

例如调查二级索引回表:

CREATE TABLE t (
  id BIGINT PRIMARY KEY,
  a INT,
  b VARCHAR(64),
  KEY idx_a(a)
) ENGINE=InnoDB;

EXPLAIN SELECT * FROM t WHERE a = 10;

源码路径:

Optimizer 选择 ref/index scan
  -> Executor 调用 handler read
     -> InnoDB secondary index lookup
        -> row_search_mvcc
           -> return PK
              -> clustered index lookup

1.8 关键数据结构

结构 说明
THD 一个客户端线程的会话上下文
TABLE 打开的表对象
handler Server 调用引擎的接口
row_prebuilt_t InnoDB 表操作上下文
buf_block_t Buffer Pool 页块
rec_t InnoDB 记录
btr_cur_t B+Tree 游标
trx_t InnoDB 事务
lock_t InnoDB 锁对象
mtr_t mini transaction

不要一开始就追所有字段,先理解生命周期和模块关系。

本章小结

MySQL 8.0 源码可以按 Server 层和 InnoDB 分开阅读。Server 层关注连接、解析、优化、执行和 Binlog;InnoDB 关注页面、B+Tree、事务、锁、MVCC、日志和后台线程。源码阅读要从可复现实验和调用链入手,用调试器和测试验证理解。

思考题

  1. sql/storage/innobase/ 的边界是什么?
  2. 一条 SELECT 的关键调用链包含哪些阶段?
  3. redo log 和 binlog 两阶段提交涉及哪些模块?
  4. 为什么建议先读 Buffer Pool、Page、B+Tree,再读事务和锁?
  5. 如何用 MTR 测试验证一个源码结论?