Skip to content
MySQL 变更与运维治理 · 第 3 篇 / 共 4 篇
领域数据与中间件
专题MySQL 专题
当前序列MySQL 变更与运维治理
阅读位置第 3 篇 / 共 4 篇当前专题第 4 个序列 / 共 7 个序列

大表在线 DDL 怎么做更稳

大表变更是数据库治理里最容易“出一次事故就记一辈子”的主题。

因为它表面看起来只是一个 alter table,但一旦判断失误,就可能引发:

  • 元数据锁把业务 SQL 全部堵住
  • 主从延迟拉长
  • binlog 激增
  • 磁盘和 IO 压力陡升
  • 发布窗口被迫回滚

先说结论

  • 大表 DDL 的核心不是“语法能不能执行”,而是“变更期间业务、复制和回滚是否可控”
  • 先判断是否支持真正的在线变更,再决定走原生 DDL、影子表工具还是灰度双写
  • 元数据锁、主从延迟和磁盘空间是大表变更最常见的三个事故点
  • 真正稳的做法一定包含预检查、低峰执行、观测和回滚预案

先分清你在改什么

大表 DDL 不能一概而论。
不同变更类型,风险差异非常大。

常见分成三类:

1. 元数据级轻变更

比如部分版本下的字段重命名、默认值调整、注释变更。
这类可能很快,但仍可能短暂拿元数据锁。

2. 支持在线算法的结构变更

例如某些加索引、加列、修改表选项,可以走 ALGORITHM=INPLACE 或更轻的能力。

3. 需要重建表的数据级重变更

比如:

  • 改字段类型
  • 改主键
  • 重排序列
  • 某些不支持在线算法的操作

这类往往风险最大,可能伴随整表重建。

为什么大表变更容易出事故

因为它不只是数据库内部慢一点,而是会牵动整条链路。

1. 元数据锁会堵住正常业务

很多人以为 DDL 卡住只是自己那条命令慢。
实际上 DDL 需要拿元数据锁,如果前面有长事务没释放,DDL 会等待;而它等待期间,后续对这张表的新 SQL 也可能被堵在后面。

这就是线上最典型的“alter 一发,全站慢”。

2. 表重建会带来大量 IO 和 binlog

如果变更需要拷表或重写数据页:

  • 磁盘写放大
  • redo / binlog 压力升高
  • 主从复制延迟扩大

3. 风险不是只在主库

主库变更成功不代表没事。
从库回放 DDL 慢、磁盘不足、复制中断,都会让风险延后爆发。

原生在线 DDL 不要盲信

很多文章会说 MySQL 8 支持在线 DDL,于是团队就觉得可以放心直接改。
这很危险。

你至少要先确认:

  • 当前 MySQL 版本
  • 当前引擎
  • 当前操作是否真的支持在线算法
  • 是否仍会拿 MDL
  • 是否仍会重建表

“支持 online”不等于“完全无感”。

常见更稳的三种做法

1. 原生 DDL + 明确算法和锁级别

适合本身支持轻量在线变更的操作。
优势是链路最短,但前提是你要足够确定风险边界。

2. 影子表工具

比如 pt-online-schema-changegh-ost 这类思路:

  • 建新表
  • 增量同步数据
  • 最后切换表

它们的价值在于把“重变更”拆成更可控的渐进过程。

3. 应用层灰度改造

当字段变更对业务语义影响很大时,更稳的方式常常不是一次性 DDL,而是:

  • 先加新列
  • 应用双写
  • 回填历史数据
  • 读流量灰度切换
  • 最后清理旧列

这类方式最啰嗦,但对核心表最稳。

一套实战前检查清单

大表变更前,我一般会先看这些:

  1. 表行数、索引数、磁盘大小
  2. 当前是否有长事务
  3. 当前峰值 QPS 和低峰窗口
  4. 主从延迟和从库磁盘空间
  5. 变更是否支持在线算法
  6. 有没有回滚方案

如果上面任何一项不清楚,就不要直接在生产上动。

上线过程要重点盯哪些指标

执行过程中至少要盯:

  • DDL 执行状态
  • 活跃事务和 MDL 等待
  • 主从延迟
  • 磁盘空间
  • 业务 RT 和错误率

很多团队只盯数据库命令本身,忽略业务侧指标,结果问题已经扩散了才发现。

最容易踩的几个坑

1. 发布前不清长事务

前面一个长事务占着表,DDL 一直拿不到锁。
你以为是“DDL 很慢”,其实是元数据锁排队把正常流量也堵了。

2. 只在主库评估,不看从库容量

主库挺住了,但从库回放期间磁盘打满或延迟爆炸,一样会出事故。

3. 没有分步骤的回滚设计

字段删了、索引删了、表切了之后再想回滚,成本会非常高。

4. 把所有变更堆到一个窗口

大表加列、索引调整、数据回填、应用发布一起做,风险会成倍放大。

一个更稳的变更思路

对于核心业务大表,通常推荐:

  1. 先做只增不删的兼容性变更
  2. 应用先兼容新旧结构
  3. 数据回填独立执行
  4. 灰度读写切换
  5. 最后做收尾清理

这样虽然步骤多,但每一步都可观测、可暂停、可回滚。

总结

大表在线 DDL 不是数据库语法问题,而是一次高风险生产变更。
真正决定成败的,不是你会不会写 alter table,而是你是否提前想清楚:

  • 它会不会重建表
  • 会不会堵住业务
  • 从库扛不扛得住
  • 失败后怎么收回来
延伸阅读相关文章优先当前专题,再补跨专题关联。
同一序列 · 顺着当前主线继续读冷热数据归档和清理策略怎么设计适合把计数、日志、在线变更和归档清理放在一起看。MySQL 专题 · MySQL 变更与运维治理同一序列 · 回看前文会更完整binlog、redo log、undo log 是怎么配合的适合把计数、日志、在线变更和归档清理放在一起看。MySQL 专题 · MySQL 变更与运维治理同专题其他序列 · MySQL 变更治理与数据生命周期大事务为什么会拖垮数据库适合把大事务、DDL、回填、慢 SQL 治理和归档分层放进一条持续治理主线上看。MySQL 专题 · MySQL 变更治理与数据生命周期同专题其他序列 · MySQL 事务、锁与高可用边界分库分表前最容易忽略哪些边界适合把 next-key lock、一致性读、复制延迟和分库分表边界放回同一条一致性主线上判断。MySQL 专题 · MySQL 事务、锁与高可用边界跨专题关联 · 同场景:基础学习@Conditional 系列注解怎么配合使用适合把自动装配、条件装配、Profile 和循环依赖放回 Spring Boot 启动过程里理解。Spring 专题 · Spring Boot 启动、装配与配置跨专题关联 · 同场景:基础学习保留策略和日志压缩适合哪些场景适合把副本机制、acks、批量压缩和日志组织放在一条 Kafka 投递主线上理解。Kafka 专题 · Kafka 投递链路与日志存储机制
继续阅读MySQL 变更与运维治理当前序列第 3 篇 / 共 4 篇当前专题第 4 个序列 / 共 7 个序列
往前看
上一篇binlog、redo log、undo log 是怎么配合的回到当前序列上一章上一序列MySQL 存储引擎与执行细节从第 1 篇开始:MVCC 和 Read View 怎么理解
往后看
下一篇冷热数据归档和清理策略怎么设计继续当前序列下一章下一序列MySQL 建模与查询执行路径从第 1 篇开始:宽表、范式和反范式怎么取舍

把零散经验整理成可查、可复用、可持续更新的企业级知识门户