MySQL Online DDL:高性能表结构变更指南
你提供的这段英文内容是 MySQL 官方文档中关于 Online DDL(在线 DDL)性能与并发控制 的详细说明。我们来逐段解析,帮助你深入理解其核心思想和实际意义。
🌟 一、什么是 Online DDL?
Online DDL 是指在执行数据库结构变更(如 ALTER TABLE
)时,允许其他查询和写入操作(DML)同时进行,而不需要长时间锁表。
传统方式:
ALTER TABLE
会锁住整个表 → 所有读写请求被阻塞 → 用户感知为“卡顿”或“服务中断”。
Online DDL:尽量减少锁,让 DML(INSERT/UPDATE/DELETE)和 SELECT 操作可以继续运行 → 提高系统可用性。
✅ 二、Online DDL 的优势
文档提到了四个关键好处:
优势 | 解释 |
---|---|
1. 更高的应用响应性 | 应用可以继续访问表,不会因为 DDL 而“挂起”。 |
2. 减少资源争用 | 锁更少、等待更少 → 整个数据库的扩展性更好。 |
3. 避免全表拷贝开销 | 不用像老的 COPY 算法那样复制整个表 → 节省 I/O 和 CPU。 |
4. 减少缓冲池污染 | 不需要大量读取数据到 buffer pool → 常用热数据不会被挤出去 → DDL 后性能不会突然下降。 |
👉 这些都指向一个目标:在不影响业务的前提下完成表结构变更。
🔐 三、LOCK 子句详解:控制并发级别
你可以通过 LOCK = ...
显式控制 DDL 操作期间允许的并发程度。
LOCK 选项 | 是否允许查询? | 是否允许 DML? | 使用场景 |
---|---|---|---|
LOCK=NONE | ✅ 是 | ✅ 是 | 关键业务表(如用户注册、订单),不能停服 |
LOCK=SHARED | ✅ 是 | ❌ 否 | 数仓类表,可暂停写入但不能停查询 |
LOCK=DEFAULT | 自动选择最优 | 自动选择最优 | 默认行为,推荐大多数情况使用 |
LOCK=EXCLUSIVE | ❌ 否 | ❌ 否 | 只想最快完成 DDL,且服务器空闲 |
⚠️ 注意:
- 如果你指定的
LOCK
比实际支持的还宽松(比如你想用LOCK=NONE
,但该操作必须加排他锁),语句会失败。 - 推荐先不指定
LOCK
,让 MySQL 自动决定。
🔁 四、Online DDL 的三个阶段(含元数据锁机制)
Online DDL 并非完全无锁,而是分阶段加锁,以最小化影响。
阶段 1:初始化(Initialization)
- 判断是否支持并发(基于存储引擎、语句类型、ALGORITHM、LOCK 设置)。
- 加 共享可升级元数据锁(shared upgradable metadata lock) → 防止别人改这个表的结构。
阶段 2:执行(Execution)
- 准备并执行 DDL。
- 如果需要排他锁,也只是短暂持有。
阶段 3:提交表定义(Commit Table Definition)
- 升级为 排他元数据锁(exclusive metadata lock) → 替换旧表结构,提交新结构。
- 这个锁时间很短,但必须等到所有并发事务释放锁后才能获得。
📌 关键点:
- 一个长事务(哪怕只是
SELECT
)会持有元数据锁 → 导致 DDL 卡住。 - 一旦 DDL 请求了排他锁,后续所有对该表的操作都会被阻塞,直到 DDL 完成。
🧪 五、案例演示:锁等待问题
-- Session 1
START TRANSACTION;
SELECT * FROM t1; -- 持有共享元数据锁-- Session 2
ALTER TABLE t1 ADD COLUMN x INT; -- 等待排他锁(卡住)-- Session 3
SELECT * FROM t1; -- 被 Session 2 的等待请求阻塞!
此时:
- Session 2 在等 Session 1 提交或回滚。
- Session 3 被 Session 2 “排队挡住了”。
📌 这就是为什么一个简单的 DDL 可能导致整个表“雪崩式”不可用的原因!
🔍 查看方法:
SHOW FULL PROCESSLIST;
-- 或使用 Performance Schema
SELECT * FROM performance_schema.metadata_locks;
⚙️ 六、如何判断 DDL 操作快慢?
文档建议用 rows affected
来判断操作是否高效:
操作 | 示例 | rows affected | 说明 |
---|---|---|---|
快速操作(不涉及数据) | ALTER TABLE t1 ALTER COLUMN c1 SET DEFAULT 5; | 0 rows affected | 元数据变更,INSTANT |
中等操作(不复制表) | ALTER TABLE t1 ADD INDEX idx(c1); | 0 rows affected | INPLACE,但耗时可能长 |
慢操作(重建表) | ALTER TABLE t1 MODIFY c1 BIGINT; | 1671168 rows affected | COPY 算法,复制整表 |
💡 实践建议:
- 先克隆一个小表测试 DDL。
- 观察
rows affected
是否为 0。 - 若非零,说明要复制全表 → 建议在低峰期操作。
📊 七、如何监控 DDL 进度?
使用 Performance Schema 监控:
-- 查看当前阶段
SELECT * FROM performance_schema.events_stages_current
WHERE EVENT_NAME LIKE 'stage/innodb/alter%';
这能告诉你 ALTER TABLE
到了哪一步(如:排序索引、应用日志等)。
🤔 八、为什么 Online DDL 有时比 COPY 更慢?
这是个反直觉的现象,原因如下:
- Online DDL 支持并发 DML → 必须记录这些并发修改(称为“log”)。
- 在 DDL 结束前,要把这些“增量变更”合并回去。
- 这个过程增加了总耗时。
✅ 但是:
- 虽然总时间更长,但用户体验更好(页面不卡)。
- 对比:
COPY
:快但全程锁表 → 用户卡 30 秒。INPLACE
:慢一点但用户几乎无感。
📌 所以,“性能”不只是速度,还包括可用性和响应性。
✅ 总结:如何理解这段内容?
核心概念 | 理解要点 |
---|---|
Online DDL 的目标 | 在不影响业务的情况下修改表结构 |
实现方式 | 尽量避免锁表,使用 INPLACE / INSTANT 算法 |
LOCK 子句 | 控制并发级别,按需选择 NONE / SHARED / EXCLUSIVE |
元数据锁(MDL) | DDL 最后一步需要排他锁,可能被长事务阻塞 |
性能判断 | 看 rows affected :0 表示不复制表,非 0 表示重建表 |
监控手段 | 用 SHOW PROCESSLIST 和 performance_schema 查锁和进度 |
权衡取舍 | Online 更稳但可能稍慢;COPY 更快但会中断服务 |
💡 实际建议(给 DBA 和开发)
- 避免长事务,尤其是只读事务不要长时间不提交。
- 大表变更前先测试小表,看是否
rows affected > 0
。 - 优先使用
ALGORITHM=INPLACE
或INSTANT
。 - 生产环境 DDL 加上
LOCK=NONE
或LOCK=SHARED
,防止意外锁死。 - 监控 MDL 锁等待,及时发现阻塞源头。
如果你有具体的场景(比如:“我想给一个千万级订单表加字段,怎么做?”),我可以进一步给出操作建议。