工程防护 / 数据库变更
English

数据库变更

改表结构期间,旧代码照常运行。

更新于 2026年11月5日查看 Markdown
本页内容

回滚代码救不回已删除的列,也撤销不了回填。

让 AI agent 规划迁移

Prompt
审查 [Jira 编号、PR 链接或 diff] 里的表结构和数据变更。
如果是 Jira ticket,通过已连接的 Jira MCP 或已认证的 acli 读取描述、验收标准和评论;访问不了就让我粘贴详情。
阅读仓库里的迁移和部署说明。拆出几个阶段,保证新旧应用版本都能正常工作,数据库操作的规模可控,并写明每个阶段怎么撤销。
列出各个阶段、进入下一阶段前需要的证据,以及所有不可逆的操作。
说明本页列出的测试哪些已在项目测试套件里。能自动化的补上,其余的列出来。
不要运行迁移或回填。

分几次发布修改一列

  • 旧代码必须能在新表结构上运行。先迁移,再部署依赖它的代码。

    注意整个滚动部署期间都要成立,因为这时新旧版本同时在跑。

  • 绝不在一次发布里重命名或删除。扩展、切换、收缩各自单独发布;回填在扩展和切换之间运行。等运行中的代码都不再用旧列,才能删掉它。

例如,用 full_name 替换 display_name:

  1. 阶段 1扩展新增 full_name,两列同时写。
  2. 阶段 2回填分批复制旧值,可中断后续跑,绝不覆盖更新的值,直到每一行都一致。
  3. 阶段 3切换改为读 full_name。只要还可能回滚,就继续两列同时写。
  4. 阶段 4收缩停止使用 display_name(Rails 里用 ignored_columns),下一次发布再删掉它。
  • 上一版本的应用在新表结构上仍能通过冒烟测试。

让每个迁移都能安全部署

  • 迁移每次部署只跑一次,作为独立步骤。绝不放进应用的启动命令。

    注意否则每个实例、每次重启都会走迁移流程,互相抢锁。

  • 给迁移设一个较短的锁超时:在繁忙的表上等锁的迁移会直接放弃,而不是把后面所有查询都堵住。参见 PostgreSQL。
  • 不在事务里运行的迁移(例如并发建索引),中途失败后必须能安全重跑。并发建索引失败后,会留下一个无效索引。PostgreSQL。
  • 回填作为可续跑的任务运行,不放进表结构迁移。
  • 涉及大表或繁忙的表时,先在 staging 用生产规模的数据跑一遍迁移,把耗时和加锁情况写进发布记录。

先确认删除会删掉什么

  • 预览要删的确切行和数量,包括关联行、文件和排队中的任务。检查租户范围和级联删除。
  • 定好这次是软删除(隐藏)还是永久删除,写明哪些能恢复、从哪个恢复点恢复。
  • 大批量删除要分批、可重新开始;数量和预期不符就停下。生产环境的删除需要明确批准。