订阅更新

给大表加字段加索引,结果库卡死了——Online DDL怎么做?

MySQL手册 第 12 题 约 2 分钟读完

本文目录
  1. 先说结论
  2. 为什么直接ALTER TABLE会卡死?
  3. 正确做法:pt-online-schema-change
  4. 实战踩坑:一次生产事故
  5. 总结

先说结论

MySQL 5.6+支持Online DDL,大多数ALTER TABLE操作不会锁表。但有些操作仍然危险,尤其是大表。生产环境推荐用pt-online-schema-change或gh-ost工具。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

给生产环境的大表加字段或加索引,是最容易引发生产事故的操作之一。我见过因为一条ALTER TABLE导致整个服务不可用半小时的事故。今天把原因和正确做法讲清楚。

为什么直接ALTER TABLE会卡死?

问题一:长时间持有MDL锁

ALTER TABLE会获取元数据锁(MDL锁)。如果有长事务在运行(比如一个没有提交的SELECT),ALTER TABLE会等待这个事务结束。更糟糕的是,ALTER TABLE的MDL锁请求会阻塞后续所有的DML和SELECT,导致雪崩。

问题二:大表重建时间长

有些DDL操作(比如修改列类型)需要重建B+树,几千万行的表可能要跑几十分钟。这期间表虽然可读写,但IO压力巨大,影响其他查询性能。

正确做法:pt-online-schema-change

原理是:

1. 创建一张新表(已经是修改后的结构)

2. 慢慢把旧表数据复制到新表(分批复制,不影响线上服务)

3. 通过触发器同步复制期间的增量变更

4. 复制完成后,原子地重命名表(旧表改名、新表改为原名)

# pt-online-schema-change 示例
pt-online-schema-change \
  --alter "ADD INDEX idx_status (status)" \
  --execute \
  --chunk-size=1000 \
  --max-lag=1 \
  D=mydb,t=orders

--max-lag=1表示如果主从延迟超过1秒就暂停复制,避免影响业务。这个细节很重要。

实战踩坑:一次生产事故

我在元宇宙社交App时,有个同事直接在生产环境执行了ALTER TABLE给一张2000万行的表加字段。刚好有一个长事务没有提交,ALTER TABLE被 MDL锁阻塞,后续所有查询都被堵住。服务不可用了20分钟,直到kill掉那个长事务才恢复。

从那以后我们的规矩是:生产环境禁止直接执行ALTER TABLE,必须用pt-osc或gh-ost。

总结

生产环境给大表做DDL,一定要用pt-online-schema-change或gh-ost。直接ALTER TABLE的风险在于MDL锁和重建时间。面试时能说清楚“为什么危险”和“正确做法”,再加一个踩坑故事,非常有说服力。

下一篇聊一个每个后端开发都会遇到的问题:连接池参数怎么配?“Too many connections”怎么解决?

你们生产环境怎么做DDL的?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器