Article
数据库变更怎么做更安全:迁移节奏与回滚意识
数据库变更怎么做更安全:迁移节奏与回滚意识
能跑通 AutoMigrate 不代表能安全改生产库。博客早期表结构还在变时,随便改问题不大;一旦有真实文章、评论、上传元数据,任何破坏性变更都值得放慢。安全迁移的核心不是工具选择,而是节奏与可回滚性。可以把每次结构变更当成一次小型发布,而不是「顺便改一下」。
先分类变更风险
按危险程度大致分三档:
- 可加且兼容:新增可空列、新增索引(仍要评估锁)
- 行为变化:改默认值、加非空约束、改枚举含义
- 破坏性:删列、改类型、改主键、拆表
第 1 档可以常规发布;第 2、3 档要有明确窗口、备份与回滚预案。把变更写进发布说明:改了哪张表、为什么改、如何验证、失败怎么退。哪怕只有你一个人维护,三个月后的你也会感谢现在的记录。
扩缩分两步,比一步到位更稳
想把「状态字符串」改成更严谨的枚举,或拆分大字段,常见安全节奏是:
- 先加新列 / 新表,双写或背后回填
- 读路径切到新结构
- 确认无误后再移除旧列
一步「改类型 + 删旧字段」在大表上既慢又难回滚。小博客表也许几秒结束,但习惯要在小表上练出来。回填脚本要可重复执行(幂等),并打印进度;中途失败应能续跑,而不是从头擦库。
对「把可空列改成非空」这类变更,先回填所有空值、确认应用不再写入 NULL,再加约束。顺序反了,迁移会在生产上直接失败,而应用可能已经部分发布。
索引变更也是变更
「只是加个索引」也可能长时间占资源,影响写入。大表考虑在线 DDL 与低峰执行。加完用慢查询与 EXPLAIN 验证收益;没有收益的索引要懂得删,而不是永远堆着。删除索引前确认没有被报表 SQL 依赖——「用不上的索引」有时只是你没看到那条周级任务。
与应用发布的先后顺序
基本原则:
- 向后兼容的数据库变更可以先于应用:先加列,再发读新列的代码
- 删除字段:通常先发不再读写旧列的应用,稳定后再删列
- 不兼容变更不要让新旧应用实例长期共存
滚动发布时,新旧二进制会短暂同时在线。如果迁移假设「所有实例已是新版」,就容易踩坑。单实例个人站也一样:先想清楚「这一分钟内旧代码是否还可能被请求打到」。
备份与演练
迁移前备份不只是心理安慰。至少会做逻辑备份或快照,并确认恢复步骤你走过一遍。从没恢复过的备份,等于没有备份。备份文件的权限与存放位置也要注意,别把含数据的 sql 丢进可公开同步的目录。
回滚分两种:
- 代码回滚:应用回到旧版,要求库结构仍兼容旧版
- 数据回滚:从备份恢复或执行反向迁移;破坏性变更常常只能靠备份
所以破坏性变更前要问:倘若要回退应用,当前库还能撑住旧代码吗?如果不能,这次发布就不该在毫无窗口的工作日傍晚硬做。
博客实践建议
用版本化 SQL 或迁移工具管理结构,而不是只靠 AutoMigrate。种子数据与迁移分离:种子可以反复跑于空库;迁移必须可追踪、可审查。生产关闭自动「危险迁移」。每次发涉及表结构的版本,验证清单至少包括:关键列表能开、后台能发文、评论审核仍正常。
本地用生产脱敏副本练习一次迁移,是最便宜的风险控制。发现脚本有 bug 时,代价只是本地时间,而不是线上半夜回档。
小结
安全迁移是工程节奏问题:兼容先行、双阶段扩缩、发布顺序配合、备份可恢复。表很小也不能用「直接上手改」当默认策略;把纪律留在小项目里,日后表变大时才不必靠运气。数据库变更不可怕,可怕的是变更时没有退路。