扩展-收缩迁移是什么
把破坏性结构变更拆成安全序列:加新结构(扩展)→ 双写与回填 → 切换读取 → 移除旧结构(收缩),每一步都可独立回滚,任意时刻新旧代码都能工作。价值在于把一次危险变更变成多次安全变更,代价是多几个版本的观察期与回填窗口。适用场景:重命名列、改类型、拆分表、迁移存储格式。
四个阶段
| 阶段 1 扩展 | 新增列、表或索引(兼容旧代码) |
|---|---|
| 阶段 2 迁移 | 双写 + 回填历史数据 + 校验一致性 |
| 阶段 3 切换 | 读切到新结构,观察 |
| 阶段 4 收缩 | 确认无依赖后删除旧结构 |
各阶段回滚点
| 阶段 | 回滚方式 | 前提 |
|---|---|---|
| 扩展后 | 停用新结构 | 无外部依赖 |
| 双写期 | 停双写回旧读 | 旧结构完整 |
| 切换后 | 读切回旧结构 | 双写仍在 |
| 收缩前 | 保持原样 | 观察期未结束 |
典型使用场景
- 列重命名:新列、双写、切读、删旧列四步替代一次重命名
- 类型变更:建新类型列按步迁移,避免一次性转换锁表
- 表拆分:先建新表双写,读切换后再停止写旧表
- 大表索引重建:新索引建好后再切换查询路径
- 存储迁移:双写新存储,校验一致后关闭旧路径
- 回填开关:回填任务支持暂停与续跑,中断后从断点继续而不全量重来
序列示意(重命名字段)
序列示意(重命名字段)
-- 1. 加新列
ALTER TABLE orders ADD COLUMN ref_no text;
-- 2. 双写并分批回填
UPDATE orders SET ref_no = legacy_ref WHERE ref_no IS NULL; -- 分批执行
-- 3. 读切换到 ref_no,观察稳定
-- 4. 停止双写,删除旧列每步之间按天或周留观察窗:数据量越大,回填与校验越要拆批执行。
双写要考虑写失败策略:两个写入点一个失败时以哪边为准、如何补偿,先定清楚再上线。
校验先行:回填后跑行数、抽样与聚合比对,校验通过才允许切读;观察期设好时长与错误率阈值,达标再进入收缩。