标准答案

  1. 扩展阶段只做向后兼容操作,例如新增可空列、创建新表、新索引或新增枚举值,不立即删除旧结构。
  2. 应用发布后以明确策略回填历史数据,并在必要时双写、双读或设置兼容层,保证新旧版本同时运行。
  3. 切流前要校验数据一致性、观察读写路径、监控错误和准备开关或回滚路径。
  4. 收缩阶段在所有旧版本、异步任务、报表和下游订阅都不再依赖旧字段后再执行。
  5. 每个阶段应独立发布、可验证、可暂停,避免把不可逆 DDL 和代码切换绑成一次风险操作。

题目解析

生产环境常有滚动发布、队列积压、长期运行任务和多个服务版本共存。若先删列再发代码,旧实例会立刻报错;若代码先只读新列而回填没完成,又会出现空数据。扩展—迁移—收缩就是为这些时序问题留出空间。

迁移完成的证据不能只是脚本跑过。需要确认旧字段读取量归零、回填校验通过、监控稳定、回滚窗口结束,并记录 schema 版本与应用版本关系。

代码示例

将姓名从单字段拆成结构化字段时,先新增、回填和双写,最后才移除旧列。

sql
-- 扩展:保持旧列仍可用
ALTER TABLE users ADD COLUMN display_name VARCHAR(128) NULL;

-- 分批回填:由任务按主键范围执行并记录进度
UPDATE users
SET display_name = name
WHERE id > ? AND id <= ? AND display_name IS NULL;

-- 切流和验证完成后,才在后续发布中删除旧列

常见误区

  • 在同一次发布里删除旧列并部署依赖新字段的代码,没有为旧实例和回滚留兼容窗口。
  • 一次性全表回填,不限批次、不监控复制和锁,拖慢线上业务。

作者信息