这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 MySQL 8.0 的数据字典支持原子 DDL,使元数据变更要么提交要么回滚。执行层面仍要区分 INSTANT、INPLACE 和 COPY,以及锁和并发 DML。
25.1 原子 DDL
prepare dictionary
-> storage engine prepare
-> commit dictionary
-> post DDL
原子性解决:
.frm与引擎元数据不一致;- DDL 中断后字典残留;
- 部分提交状态;
- 重复重试困难。
25.2 算法
| 算法 | 特点 |
|---|---|
| INSTANT | 修改元数据 |
| INPLACE | 引擎内变更 |
| COPY | 重建并复制数据 |
指定方式:
ALTER TABLE t ADD COLUMN c INT, ALGORITHM=INSTANT;
ALTER TABLE t ADD INDEX idx_c(c), ALGORITHM=INPLACE;
如果操作不支持指定算法,DDL 会失败而不是降级。
25.3 并发 DML
ALTER TABLE t ADD INDEX idx_c(c), ALGORITHM=INPLACE, LOCK=NONE;
锁模式:
| 模式 | 含义 |
|---|---|
| NONE | 允许并发 DML |
| SHARED | 允许读、阻塞写 |
| EXCLUSIVE | 阻塞读写 |
即使 LOCK=NONE,DDL 仍需要短暂元数据锁,长事务会阻塞它。
25.4 Online DDL 阶段
MDL exclusive probe
-> prepare
-> build
|-- concurrent DML log
+-- read data
-> apply row log
-> commit
-> final MDL
大表 Online DDL 仍可能占用:
- 临时磁盘;
- row log;
- redo;
- CPU 和 IO;
- 长时间 MDL 窗口。
25.5 常见操作
| 操作 | 常见方式 |
|---|---|
| 加列 | 8.0 多数可 INSTANT,受位置和版本限制 |
| 删列 | 通常 INPLACE 或 COPY |
| 加索引 | INPLACE |
| 删索引 | INPLACE |
| 修改列类型 | 常 COPY |
| 更改主键 | 重建 |
| 字符集转换 | 可能 COPY |
必须按当前小版本验证。
25.6 第三方在线 DDL
gh-ost 和 pt-online-schema-change 通过影子表和增量同步减少锁影响。
选择:
| 工具 | 思路 |
|---|---|
| gh-ost | binlog 异步复制到影子表 |
| pt-osc | 触发器同步 |
使用前要评估磁盘、binlog、延迟、触发器兼容性和切换窗口。
25.7 生产流程
评估算法和锁
-> 测试库演练
-> 测量耗时和空间
-> 检查长事务
-> 低峰执行
-> 监控 MDL/IO/延迟
-> 验证结构和数据
本章小结
原子 DDL 保证数据字典一致性,执行代价仍由算法和锁决定。生产 DDL 要先确认当前版本支持情况,评估空间和锁窗口,并在低峰执行或使用在线工具。
思考题
- 原子 DDL 是否等于不锁表?
- INSTANT、INPLACE、COPY 的差异是什么?
- 为什么
LOCK=NONE仍可能等待 MDL? - Online DDL 的 row log 有什么代价?
- 什么时候选择 gh-ost 或 pt-osc?