MySQL在线DDL:零停机改表实战指南
你提供的这段内容是 MySQL 官方文档的 17.12 节:InnoDB and Online DDL,它详细介绍了 MySQL(尤其是 InnoDB)从 5.6 开始引入并持续优化的一项核心功能:在线 DDL(Online DDL)。
🌟 一句话总结:
Online DDL 允许你在修改表结构(如加字段、建索引等)的同时,依然可以正常读写数据,几乎不影响业务运行。
这在现代高可用、高并发的生产环境中至关重要。
我们来逐段深入解读,并用通俗语言 + 实战建议帮助你理解。
🔹 17.12.1 Online DDL Operations(支持的在线 DDL 操作)
✅ 什么是 Online DDL?
传统的 ALTER TABLE
会锁表、复制整个表,耗时长、服务中断。而 Online DDL 改进了这一点:
- Instant(瞬间完成):某些操作只需修改元数据,不碰数据文件。
- In-Place(原地修改):不创建临时表,直接在原表上改,但仍需少量锁。
- Copy(表复制):老方式,效率低,已尽量避免。
📊 不同操作类型对比(MySQL 8.0+)
操作 | ALGORITHM | 是否在线? | 说明 |
---|---|---|---|
ADD COLUMN (末尾) | INSTANT (8.0.12+) | ✅ 几乎无锁 | 只改元数据 |
ADD INDEX | INPLACE | ✅ 支持 DML | 构建索引时允许读写 |
DROP INDEX | INPLACE | ✅ 完全在线 | 删除快 |
MODIFY COLUMN 类型变更 | COPY 或 INPLACE | ❌/⚠️ | 大部分需要复制表 |
ADD PRIMARY KEY | INPLACE | ✅ 但需排序 | 可能较慢 |
CHANGE COLUMN 名称或类型 | 多数 COPY | ❌ | 不推荐在线做 |
💡 提示:
INSTANT
是 MySQL 8.0.12 的重大优化,比如加字段几乎“零延迟”。
🔹 17.12.2 Online DDL Performance and Concurrency(性能与并发控制)
⚙️ 你可以通过两个关键子句控制行为:
1. ALGORITHM={INSTANT \| INPLACE \| COPY}
- 强制使用某种算法。
- 用于调试或降级兼容。
2. LOCK={DEFAULT \| NONE \| SHARED \| EXCLUSIVE}
- 控制 DDL 期间的并发级别。
LOCK 级别 | 允许 SELECT? | 允许 DML(INSERT/UPDATE/DELETE)? | 场景 |
---|---|---|---|
LOCK=NONE | ✅ | ✅ | 最宽松,适合高并发系统 |
LOCK=SHARED | ✅ | ❌ | 只读可用,防写入 |
LOCK=DEFAULT | 自动选择 | 自动选择 | 默认行为 |
LOCK=EXCLUSIVE | ❌ | ❌ | 完全锁表,慎用 |
✅ 推荐做法:
ALTER TABLE users ADD COLUMN phone VARCHAR(20), ALGORITHM=INPLACE, LOCK=NONE;
这样如果无法做到“不锁”,语句会立即失败,而不是卡住生产环境。
🔹 17.12.3 Online DDL Space Requirements(空间需求)
💾 空间消耗对比
算法 | 是否需要额外空间? | 说明 |
---|---|---|
ALGORITHM=INSTANT | ❌ 几乎不需要 | 只改字典 |
ALGORITHM=INPLACE | ⚠️ 少量 | 需要日志空间、排序缓冲等 |
ALGORITHM=COPY | ✅ 需要 ≥ 2倍表大小 | 创建临时表 .tmp ,风险高 |
📌 举例:一个 50GB 的表执行
ALGORITHM=COPY
,需要至少 100GB 磁盘空间!
✅ 建议:
- 监控磁盘空间。
- 尽量避免
COPY
模式。
🔹 17.12.4 Online DDL Memory Management(内存管理)
- Online DDL 在构建索引或重做表时会使用缓冲区。
- 主要参数:
innodb_sort_buffer_size
:排序用内存。innodb_online_alter_log_size
:记录 DDL 过程中 DML 变更的日志大小。
⚠️ 如果 DDL 期间有大量写入,这个日志可能溢出,导致失败。
✅ 建议:
- 对大表 DDL,提前增大:
SET GLOBAL innodb_online_alter_log_size = 1073741824; -- 1GB
🔹 17.12.5 Configuring Parallel Threads for Online DDL(并行线程配置)
从 MySQL 8.0 起,某些 DDL 操作(如创建二级索引)可以并行执行,显著提升速度。
- 使用参数:
innodb_parallel_read_threads
(默认 4) - 适用于:
ADD INDEX
等 I/O 密集型操作。
✅ 示例:
-- 提高并行度
SET SESSION innodb_parallel_read_threads = 8;
ALTER TABLE orders ADD INDEX idx_user_id (user_id);
💡 类似于“多个人一起搬砖”,加快索引构建。
🔹 17.12.6 Simplifying DDL Statements with Online DDL(简化 DDL 语句)
你不需要每次都写 ALGORITHM
和 LOCK
,MySQL 默认会自动选择最优方式。
但你可以显式指定以确保安全:
-- 安全写法:必须在线,否则失败
ALTER TABLE logs ADD COLUMN status TINYINT,ALGORITHM=INPLACE,LOCK=NONE;
✅ 好处:防止意外锁表,适合自动化脚本。
🔹 17.12.7 Online DDL Failure Conditions(失败情况)
以下情况会导致 Online DDL 失败或退化为 COPY
:
- 使用了不支持
INPLACE
的操作(如改变列字符集)。 - 指定的
LOCK
级别无法满足(如要求LOCK=NONE
但实际需要锁)。 - 磁盘空间不足。
innodb_online_alter_log
溢出(DDL 期间写入太多)。- 存在外键约束限制。
✅ 建议:在测试环境先试,查看
SHOW ENGINE INNODB STATUS
中的 DDL 日志。
🔹 17.12.8 Online DDL Limitations(限制)
当前仍有一些限制:
限制 | 说明 |
---|---|
不支持 JSON 列的某些修改 | 如修改嵌套结构 |
分区表 DDL 更复杂 | 部分操作仍需锁表 |
ALTER TABLE ... RENAME COLUMN | 8.0+ 支持,但底层可能是 COPY |
外键约束可能阻止 LOCK=NONE | 需注意依赖关系 |
ROW_FORMAT 修改可能触发复制 | 尤其是 COMPRESSED |
✅ 实战建议(DBA 必看)
场景 | 推荐做法 |
---|---|
加字段(末尾) | MySQL 8.0.12+ 用 ADD COLUMN → 几乎无感 |
加索引 | 用 ALGORITHM=INPLACE, LOCK=NONE ,避免高峰期 |
改字段类型 | 小心!可能触发 COPY ,先评估 |
删除字段 | 支持 INPLACE ,但建议先测试 |
生产环境 DDL | 永远加上 LOCK=NONE 或 LOCK=SHARED ,防止锁库 |
大表操作 | 提前调大 innodb_online_alter_log_size ,开启并行 |
🧪 示例:安全地在线加字段和索引
-- 1. 加字段(MySQL 8.0.12+ 瞬间完成)
ALTER TABLE users ADD COLUMN email VARCHAR(100) AFTER name,ALGORITHM=INSTANT,LOCK=NONE;-- 2. 加索引(允许读写)
ALTER TABLE users ADD INDEX idx_email (email),ALGORITHM=INPLACE,LOCK=NONE;-- 3. 查看是否成功
SHOW PROCESSLIST; -- 观察是否有阻塞
📈 总结:Online DDL 的三大优势
优势 | 说明 |
---|---|
高可用性 | 表不锁,服务不中断 |
节省空间 | 避免 COPY 模式占用双倍磁盘 |
提升效率 | 并行 + 快速算法(如 INSTANT) |
🚨 最后提醒
不要以为所有 DDL 都是“在线”的!
一定要:
- 查看 MySQL 官方文档 确认操作是否支持 Online。
- 在测试环境验证。
- 生产环境使用
ALGORITHM
和LOCK
显式控制行为。
如果你有具体的 DDL 语句想知道是否“在线”,或者想分析某个 DDL 为什么卡住了,欢迎贴出来,我可以帮你分析!