改表结构不停服:云上Schema演进与数据版本管理实战
本内容发表于:2026-05-20 11:33:05
浏览量
1016

改表结构不停服:云上Schema演进与数据版本管理实战

微信图片_2026-05-20_113059_261.png

去年一个客户,大促前一周要加个字段。DBA评估后说:这个表1.2亿行,ALTER TABLE预计锁表10-15分钟。业务负责人炸了:“大促前停15分钟?不可能。”

DBA也很委屈:“MySQL改表就是这样,我有什么办法。”

后来用了pt-online-schema-change,在线改,不锁表。业务无感知,字段加上了。

这是很多开发者和DBA的认知误区:改表结构一定要停服。其实不用。

今天聊聊云上Schema演进与数据版本管理。不是那种“改表要小心”的入门课,而是帮你理清楚:怎么在线改表不锁业务?怎么让新旧代码同时兼容?改错了怎么回滚?

01 ALTER TABLE为什么不锁表?

很多人对MySQL ALTER TABLE的印象还停留在5.5时代:改表就锁,锁了就等。MySQL 5.6开始支持Online DDL,大部分操作可以在线完成,不阻塞读写。

不同操作的锁表风险

操作锁表风险说明
加列(末尾)5.6+支持,只读元数据锁
加索引创建期间可读写
删索引瞬间完成
改列类型需要重建表,会锁
改列名取决于场景
加主键需要重建表
删列中到高需要重建表

那家客户加的是普通列,在MySQL 8.0里其实可以直接ALTER,锁表时间很短。但他们用的还是5.7,且表太大,直接改有风险。pt-online-schema-change是更稳妥的选择。

02 在线改表工具:pt-osc和gh-ost

当原生Online DDL不够用,或者风险太高时,用第三方工具。

pt-online-schema-change(Percona Toolkit)

原理:创建一个新表(结构已改),原表上加触发器,把增量数据同步到新表,最后原子切换。

优点:成熟稳定,支持所有MySQL版本。
缺点:需要触发器,对主从复制有影响,大表切换时短暂抖动。

gh-ost(GitHub开源)

原理:通过二进制日志同步增量数据,不依赖触发器,对主库压力更小。

优点:无触发器,更安全,负载可控。
缺点:需要binlog_row_image=FULL,对从库有额外负载。

那家客户用的是pt-osc。1.2亿行,耗时25分钟,期间业务完全正常。切换瞬间有不到1秒的抖动,应用层重试即可。

03 向后兼容:新旧代码共存的必修课

在线改表只是第一步。更难的是:改完表之后,新旧代码版本共存期间怎么办?

黄金法则:新代码要能跑在老表结构上,老代码要能跑在新表结构上。

加列场景

  • 新列要有默认值,或者允许NULL。老代码不知道这个列,INSERT时不写它,要能成功。

  • 新代码写新列,老代码读不到——业务上要能接受。

删列场景

  • 先改代码,不再读这个列。等所有代码都上线了,再删列。

  • 绝对不能先删列再改代码。顺序错了,老代码上线就报错。

改列类型场景

  • 尽量不要直接改。加新列,双写,迁移数据,切代码,删旧列。

那家客户加列时,设置了DEFAULT NULL。老代码不知道这列,INSERT不写,自动为NULL,业务正常。新代码写入,也正常。

04 灰度变更:先让一部分表尝鲜

生产环境直接改核心表,风险高。可以分步走。

策略一:先改从库,再切主库

  • 从库上先改,观察一段时间没问题,再改主库。

策略二:按表大小分批次

  • 小表先改,验证工具和流程。大表最后改。

策略三:按业务模块灰度

  • 非核心业务的表先改,核心业务后改。

那家客户的做法:先在备库上跑pt-osc,验证整个流程。然后选了一个非核心表试跑。确认没问题后,才在核心订单表上执行。

05 回滚方案:改错了怎么退

改表比改代码难回滚。代码回滚是重新部署,表结构回滚可能丢数据。

回滚策略

  • 保留旧表:pt-osc执行完后,旧表不会立即删除,会保留一段时间。出问题可以直接rename切回去。

  • 保留旧列:加列后保留一段时间再删。改列类型时,保留旧列,双写。

  • 灰度回滚:发现新表有问题,但旧表还在,可以快速切换。

注意:pt-osc执行完后,默认会删除旧表。要加--no-drop-old-table参数,保留旧表作为回滚备份。

那家客户保留了旧表24小时,确认新表没问题后才手动清理。期间如果有问题,可以秒级切回。

06 一个真实案例:加字段锁表2小时

一个客户,核心订单表5000万行。DBA直接执行ALTER TABLE orders ADD COLUMN source VARCHAR(20)。MySQL 5.7,没开Online DDL优化,表被锁了近2小时。订单业务中断,损失惨重。

事后改用pt-osc:

  • 先在从库跑,验证流程

  • 设置chunk-size=1000,分批拷贝数据

  • 设置max-load,监控主库负载,负载高了自动暂停

  • 执行耗时40分钟,业务无感知

技术负责人说:“以前觉得改表就是一条SQL的事,现在知道,改表要当发布来做——有流程、有预案、有回滚。”

写在最后

改表结构不停服,不是技术做不到,是流程没跟上。

那家客户的运维负责人后来总结了一个口诀:“加列加索引用工具,删列改列先改代码;向后兼容是底线,保留旧表做回滚;灰度先行,从库验证,大表分批别硬扛。”

下次要改表,先问自己:会锁表吗?新旧代码兼容吗?回滚方案有吗?三个问题答完,再动手。