从一张表到三十二张表
MySQL 系列第 19 篇讲过单表大 DDL 的标准打法:用 gh-ost 或 pt-online-schema-change 做在线改表——影子表拷数据、增量回放、原子改名,全程不停写。分库分表之后,这套打法没有失效,只是工作量乘以了物理表的数量:一次加字段,8 库 32 表要跑 32 轮影子拷贝。好消息藏在坏消息里——每张物理表只有几百万行,单表拷贝从八小时缩到十几分钟;真正的难点从「怎么改一张大表」变成了「怎么协调三十二次小改表,全程线上无感」。
执行纪律:小步、串行、可停
分片环境的 DDL 变更纪律三条。金丝雀先行——先只改一个库的一张表,观察十五分钟:主从延迟、锁等待、同步链路都无恙,再继续;库内串行、库间并行——同一个实例上的表逐张改(共享 IO,并发只会互相拖慢),不同实例可以并行推进,总时长约等于最慢一库的耗时;可暂停可回退——gh-ost 支持暂停与终止,批处理脚本要有断点水位,变更中断后能从断点继续而不是从头再来。整套流程走下来,32 张表的加字段通常一个低峰夜就能安全完成。
真正的深坑:新旧结构共存
比执行更难的,是变更期间新旧表结构共存的问题:32 张表要改几个小时甚至一整夜,期间新旧结构同时在线——老结构的表没有新字段,新结构的表刚加上。这一刻如果有代码写了新字段的值,落到老结构的表直接报错。所以分片环境的 DDL 有铁律:结构变更和代码变更必须分两步发布:
第一步:先发「读写都不依赖新结构」的代码(兼容新旧两种结构)
第二步:全量完成 DDL(32 张表逐张改)
第三步:再发「开始使用新字段」的代码
// 顺序反了:新代码写新字段 → 落到未改的老结构表 → 直接报错删字段反过来:先停用(代码不读写),再删除。改字段类型最凶险,走「加新列、双写、刷数据、切读、删旧列」的完整迁移小流程——本质上是一次微型数据迁移,第 14-15 篇的框架直接套用。
让 DDL 变成日常小事
治理做得好的团队,会把分片 DDL 从「应急项目」变成「日常流程」:变更脚本模板化(金丝雀、串行、断点、校验全内置),执行平台化(点按钮跑批、进度可视、异常自动暂停),评审规则化(字段评审在拆分设计期就把未来半年可能的扩展想清楚,减少变更次数本身)。最好的 DDL 是不需要 DDL——设计期多想一步,运营期少熬一夜。
结构变更的工程讲完,接下来是数据的日常代谢:历史数据堆积怎么办、归档怎么设计才安全——下一篇聊聊让主表保持轻盈的冷热分离。
评论 (0)