MySQL 8.0Notes

第 02 章:编译与调试

zjc 于 2026-01-02 发布

这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 读源码必须能构建和调试。断点、调用栈、变量和测试用例能验证推测,避免把社区博客结论直接套到当前版本。

2.1 环境准备

推荐 Linux:

工具 用途
gcc / clang 编译器
cmake 构建配置
ninja / make 构建执行
gdb / lldb 调试
git 版本管理
bison / flex Parser 生成
openssl TLS
ncurses 终端
pkg-config 依赖发现

Ubuntu 示例:

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

2.2 获取源码

git clone https://github.com/mysql/mysql-server.git
cd mysql-server
git checkout mysql-8.0.40
git submodule update --init --recursive

建议固定一个 8.0.x 小版本,并在笔记中记录 commit hash。不同小版本的结构和默认行为可能变化。

2.3 构建

mkdir build
cd build
cmake .. -GNinja \
  -DCMAKE_BUILD_TYPE=Debug \
  -DWITH_DEBUG=ON \
  -DWITH_UNIT_TESTS=OFF \
  -DWITH_BOOST=system
ninja -j$(nproc)

常用选项:

选项 说明
CMAKE_BUILD_TYPE=Debug 保留调试信息
WITH_DEBUG=ON 打开 Server debug 支持
WITH_UNIT_TESTS=OFF 减少构建时间
WITH_BOOST=system 使用系统 Boost
CMAKE_INSTALL_PREFIX 安装目录

如果依赖下载慢,可先手动准备依赖,并保持构建配置可复现。

2.4 初始化与启动

mkdir -p /tmp/mysql-test-data
./runtime_output_directory/mysqld \
  --initialize-insecure \
  --datadir=/tmp/mysql-test-data \
  --basedir=.

./runtime_output_directory/mysqld \
  --datadir=/tmp/mysql-test-data \
  --socket=/tmp/mysql-test.sock \
  --port=3306 \
  --log-error=/tmp/mysql-error.log

连接:

./runtime_output_directory/mysql \
  --socket=/tmp/mysql-test.sock \
  -uroot

2.5 gdb 调试

启动服务:

gdb --args ./runtime_output_directory/mysqld \
  --datadir=/tmp/mysql-test-data \
  --socket=/tmp/mysql-test.sock

常用断点:

b dispatch_command
b mysql_parse
b mysql_execute_command
b mysql_select
b ha_innobase::index_read
b row_search_mvcc
b trx_commit
run
bt
p thd->query()
info threads

调试技巧:

  1. 用最小 SQL 复现;
  2. 先看调用栈,再进入细节;
  3. 记录断点、线程和参数;
  4. 多线程场景关注 THD 与 InnoDB 线程;
  5. 不在生产实例上调试;
  6. Debug 断言失败时先看触发条件。

2.6 VS Code 配置

.vscode/launch.json 示例:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "mysqld",
      "type": "cppdbg",
      "request": "launch",
      "program": "${workspaceFolder}/build/runtime_output_directory/mysqld",
      "args": ["--datadir=/tmp/mysql-test-data"],
      "stopAtEntry": false,
      "cwd": "${workspaceFolder}"
    }
  ]
}

配合 clangd 或 IntelliSense 可以快速跳转结构体和函数。

2.7 MTR 测试

MySQL 测试框架位于 mysql-test/

cd mysql-test
perl mysql-test-run.pl --vardir=/tmp/mtr-vardir main.select

测试文件结构:

-- source include/have_innodb.inc
CREATE TABLE t(id INT PRIMARY KEY, v INT) ENGINE=InnoDB;
INSERT INTO t VALUES(1,1),(2,2);
SELECT * FROM t WHERE id=2;
DROP TABLE t;

MTR 价值:

  1. 固定复现步骤;
  2. 验证行为差异;
  3. 修改源码后做回归;
  4. 学习内部特性开关;
  5. 观察错误码和状态。

2.8 Debug 支持

Debug 构建可以打开更多诊断:

SET GLOBAL debug = 'd:t:o,/tmp/mysqld.trace';

InnoDB monitor:

SHOW ENGINE INNODB STATUS;
SET GLOBAL innodb_status_output=ON;
SET GLOBAL innodb_status_output_locks=ON;

performance_schema:

SELECT event_name, count_star
FROM performance_schema.events_waits_summary_global_by_event_name
ORDER BY count_star DESC
LIMIT 10;

2.9 常见构建问题

问题 处理
缺 Boost 指定系统或下载路径
bison 版本不匹配 按文档升级
内存耗尽 降低并行度
找不到 OpenSSL 安装 dev 包并检查路径
增量构建异常 清理后重建
符号缺失 确认 Debug 构建
运行目录异常 使用独立 datadir

2.10 工作流

推荐流程:

提出问题
  -> 写最小 SQL
     -> 设置断点
        -> 观察调用栈
           -> 查看结构体
              -> 对照源码
                 -> 写 MTR
                    -> 归档结论

本章小结

编译调试是源码阅读的基础。固定版本、使用 Debug 构建、维护独立数据目录、通过 gdb 查看 SQL 层和 InnoDB 关键断点,并用 MTR 固化实验结论,可以显著降低阅读误差。

思考题

  1. 为什么读源码前要记录具体版本和 commit?
  2. Debug 构建和 Release 构建在源码阅读上有什么差异?
  3. dispatch_commandmysql_parse 分别适合观察什么?
  4. MTR 测试对源码研究有什么价值?
  5. 如何构建一个可重复的调试环境?