MySQL 大表加字段、加索引的在线 DDL 方案对比

在 MySQL 运维和面试中,“大表加字段、加索引”是一个高频且经典的场景。一张几千万甚至上亿行的表,直接执行 ALTER TABLE 往往意味着长时间锁表、主从延迟飙升,甚至业务不可用。因此,理解不同在线 DDL 方案的原理、适用场景和风险,是后端开发与 DBA 的必备技能。

本文将从面试题的角度出发,系统对比 MySQL 大表加字段、加索引的几种主流在线 DDL 方案,包括原生 Online DDL、pt-online-schema-change、gh-ost 以及 MySQL 8.0 的 Instant Add Column,并给出选型建议。

一、为什么大表 DDL 如此危险

在讨论方案之前,先明确问题的根源。MySQL 5.6 之前的 ALTER TABLE 几乎都是 Copy 方式:创建新表、逐行拷贝数据、重建索引,全程持有表锁,阻塞写操作。对于大表,这个过程可能持续数小时。

即使 MySQL 5.6 引入了 Online DDL,也并非所有操作都能真正做到“在线”。例如:

  • 加字段:通常支持 In Place,但早期版本仍可能重建表。
  • 加索引:一般支持 In Place,但需要扫描全表构建索引,期间仍可能短暂锁表。
  • 修改字段类型:往往只能 Copy,锁表时间长。

因此,面试中常问:“一张 5000 万行的表要加一个字段和索引,你会怎么做?”这实际上是在考察你对在线 DDL 工具和原理的掌握。

二、方案一:MySQL 原生 Online DDL

2.1 原理

MySQL 5.6 及以上版本支持 Online DDL,通过 ALGORITHM=INPLACELOCK=NONE 尽量在不阻塞 DML 的情况下完成。其核心机制是:

  1. 在 DDL 执行期间,允许并发 DML 操作。
  2. 将 DML 产生的增量日志记录到 Online Log 中。
  3. DDL 完成后,应用增量日志,保证数据一致。

2.2 加字段

对于 ALTER TABLE t ADD COLUMN c INT,在 MySQL 5.7 中通常支持 ALGORITHM=INPLACE, LOCK=NONE,但依然需要重建表(因为行格式变化)。在 MySQL 8.0 中,如果使用 ALGORITHM=INSTANT,则只需修改数据字典,瞬间完成,不重建表。

-- MySQL 8.0 瞬间加字段
ALTER TABLE t ADD COLUMN c INT, ALGORITHM=INSTANT;

2.3 加索引

ALTER TABLE t ADD INDEX idx_c (c), ALGORITHM=INPLACE, LOCK=NONE;

加二级索引通常支持 In Place 且不阻塞 DML,但需要扫描全表并排序,对 IO 和 CPU 压力较大。

2.4 优缺点

  • 优点:无需额外工具,原生支持,操作简单。
  • 缺点:大表加字段仍可能重建表,耗时久;加索引会消耗大量 IO;主从延迟难以避免;对业务高峰不友好。

三、方案二:pt-online-schema-change

3.1 原理

pt-online-schema-change(简称 pt-osc)是 Percona Toolkit 中的工具。其核心流程:

  1. 创建一张与原表结构相同的新表,并在新表上执行 DDL。
  2. 在原表上创建触发器,将 INSERT、UPDATE、DELETE 操作同步到新表。
  3. 分批拷贝原表数据到新表。
  4. 拷贝完成后,用 RENAME 交换表名。

3.2 使用示例

pt-online-schema-change \
  --alter "ADD COLUMN c INT, ADD INDEX idx_c (c)" \
  D=test,t=t \
  --execute

3.3 优缺点

  • 优点:不锁原表,支持加字段、加索引、修改字段等;可限速,降低对主库压力。
  • 缺点:依赖触发器,有额外写入开销;触发器可能与业务逻辑冲突;外键场景受限;需要额外磁盘空间;RENAME 瞬间仍会短暂锁表。

四、方案三:gh-ost

4.1 原理

gh-ost 是 GitHub 开源的在线 DDL 工具,设计上摒弃了触发器。其流程:

  1. 创建新表并执行 DDL。
  2. 伪装成从库,读取原表的 binlog,将增量变更应用到新表。
  3. 分批拷贝原表数据。
  4. 通过 RENAME 交换表名。

4.2 使用示例

gh-ost \
  --host=127.0.0.1 \
  --database=test \
  --table=t \
  --alter="ADD COLUMN c INT, ADD INDEX idx_c (c)" \
  --execute

4.3 优缺点

  • 优点:无触发器,对原表侵入小;支持动态调整限速;可暂停、恢复;主从延迟可控。
  • 缺点:需要 binlog 为 ROW 格式;需要额外磁盘空间;RENAME 瞬间锁表;学习成本略高。

五、方案四:MySQL 8.0 Instant Add Column

5.1 原理

MySQL 8.0.12 引入 Instant Add Column,8.0.29 进一步支持 Instant Add/Drop Column 任意位置。其核心是只修改数据字典中的元数据,不重建表、不拷贝数据。对于已有行,新增列的值通过默认值在读取时动态填充。

5.2 限制

  • 只能加列,不能加索引。
  • 新增列必须是默认值或允许 NULL。
  • 不支持压缩表、临时表等部分场景。
  • 如果表已有 INSTANT 列,再加列可能仍为 INSTANT,但有版本限制。

5.3 使用示例

ALTER TABLE t ADD COLUMN c INT DEFAULT 0, ALGORITHM=INSTANT;

5.4 优缺点

  • 优点:秒级完成,几乎无锁,对主从延迟无影响。
  • 缺点:仅限加字段,不能加索引;有版本和场景限制。

六、方案对比与选型建议

方案 加字段 加索引 锁表风险 主从延迟 额外空间 适用场景
原生 Online DDL 支持,可能重建表 支持 低到中 可能较高 可能需 小表或低峰期
pt-osc 支持 支持 可控 需要 无外键、可接受触发器
gh-ost 支持 支持 可控 需要 大表、高并发、无触发器
Instant Add Column 支持 不支持 极低 不需要 MySQL 8.0 加字段

选型建议

  1. 如果只是加字段且使用 MySQL 8.0,优先使用 ALGORITHM=INSTANT
  2. 如果需要加索引或修改字段,且表非常大、业务不能停,优先选择 gh-ost。
  3. 如果环境不允许使用 gh-ost,可考虑 pt-osc,但需注意触发器和外键限制。
  4. 如果表不大,或可在低峰期操作,原生 Online DDL 足够。
  5. 无论哪种方案,都应先在从库或测试环境验证,并监控主从延迟。

七、面试常见追问

  • 问:gh-ost 和 pt-osc 的核心区别是什么?
    答:gh-ost 无触发器,通过 binlog 同步增量;pt-osc 依赖触发器。gh-ost 对原表侵入更小,但要求 ROW 格式 binlog。

  • 问:Instant Add Column 为什么快?
    答:只修改数据字典,不重建表、不拷贝数据,已有行读取时动态填充默认值。

  • 问:加索引一定会锁表吗?
    答:MySQL 5.6+ 加二级索引通常支持 LOCK=NONE,但 DDL 开始和结束阶段仍可能短暂持有元数据锁。

  • 问:如何降低主从延迟?
    答:使用 gh-ost 或 pt-osc 的限速功能,分批拷贝,避开高峰,必要时先扩展从库。

八、总结

大表加字段、加索引没有“银弹”,需要根据 MySQL 版本、表大小、业务容忍度、运维工具链综合选择。MySQL 8.0 的 Instant Add Column 让加字段变得前所未有的轻量,但加索引仍需依赖 Online DDL 或第三方工具。掌握 pt-osc 和 gh-ost 的原理与差异,是应对面试和实际生产问题的关键。

在实际操作中,永远记住:先备份、先在从库验证、先限速、先监控。DDL 不是简单的 SQL 执行,而是一次需要精心策划的在线变更。

未经允许不得转载:任鹏个人博客 » MySQL 大表加字段、加索引的在线 DDL 方案对比

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏