写可回滚的数据迁移脚本
一次交付迁移、回滚和校验,先在少量数据上走通
你是负责线上数据迁移的后端工程师。根据下面的表结构和变更目标,输出三部分:1)迁移脚本:分批执行、可重入、每批有上限,避免长事务锁表;2)回滚脚本:说明哪些操作不可逆、回滚后如何核对;3)校验 SQL:在回填后、切换前、回滚前各跑一次,给出预期结果和阈值。先指出方案里最可能丢数据的一步,再给脚本。不要假设可以停机。 [表结构/变更目标/数据量级]
使用建议
先在影子表或 1% 数据上跑一遍;可重入和回滚都验证过,再安排正式上线窗口。
适合什么场景
- 要给千万行的订单表加一个非空字段并回填,停机窗口只有几分钟。
- 要改名或拆表,属于不可逆操作,执行前需要把回滚路径和数据核对方式写清楚。
不适合的场景
- 只是加一个允许 NULL 的新列、不需要回填:一条 DDL 就够,不必写迁移脚本。
- 字段语义还没定、表结构还在天天改:先定模型;这时写脚本只会返工。
示例
输入
-- orders:约 1200 万行,MySQL 8.0 ALTER TABLE orders ADD COLUMN region_code VARCHAR(8) NOT NULL DEFAULT ''; UPDATE orders SET region_code = ...;
你会得到
全表 UPDATE 会在整个回填期间持锁,直接超过停机窗口;应改成按主键每批 5000 行,并让每批都能重跑。回滚并不对称:DROP COLUMN 会把回填的数据一起丢掉,所以每批回填后都要跑 `region_code = ''` 的计数校验,并在回滚前记录基线。预期行数要写死,不能只说「检查一下数据」。
常见误用
- 先在数据量很小的预发库跑全表 UPDATE:锁表时间根本不会暴露,上线才炸。
- 只验证迁移成功、不验证回滚:真出事时才发现 DROP COLUMN 把回填数据一起删了。
可以这样改
- 加一句「假设只能停机 5 分钟」,它会改用分批加双写,而不是一条大 UPDATE。
- 要求「中途失败从哪一步续跑」,能把不可重入的脚本挡在评审之前。