数据库迁移脚本管理实践:不要手改生产库
数据库结构变化最怕什么?
不是写错一个字段。
而是:
1 | 开发环境改了 |
代码可以 Git 回滚。
数据库如果靠手工改,很快就会失控。
所以项目只要进入多人协作,就应该认真管理数据库迁移脚本。
一、什么是数据库迁移
数据库迁移就是把数据库结构变化写成可追踪脚本。
比如:
1 | ALTER TABLE users ADD COLUMN avatar_url VARCHAR(255); |
或者:
1 | CREATE TABLE orders ( |
这些脚本按顺序执行,数据库就能从旧版本升级到新版本。
迁移管理的目标是:
1 | 任何环境都能知道自己执行到了哪一步。 |
二、不要直接在生产库点点点
很多事故来自“我就临时改一下”。
比如:
1 | 在生产库加字段 |
或者:
1 | 生产库字段类型被手动改了 |
数据库结构是代码的一部分。
既然代码要走 Git,数据库结构也应该走脚本。
原则很简单:
1 | 可以临时排查 |
真要紧急修复,也要事后补迁移脚本,并确认所有环境一致。
三、迁移文件命名要有顺序
迁移脚本最重要的是顺序稳定。
常见命名方式:
1 | 20260612195700_create_users_table.sql |
也可以用递增版本号:
1 | 001_create_users_table.sql |
我更喜欢时间戳。
因为多人同时开发时,时间戳更不容易冲突,也更容易看出脚本产生顺序。
目录可以这样放:
1 | db/ |
不要把迁移脚本散落在文档、聊天记录和个人电脑里。
四、需要一张 schema_migrations 表
迁移工具通常都会维护一张表,记录哪些脚本执行过。
类似:
1 | CREATE TABLE schema_migrations ( |
每执行一个迁移文件,就插入一条版本记录。
这样应用启动或部署时,就能判断:
1 | 哪些迁移已经执行 |
不要只靠“我记得执行过”。
人脑不是迁移系统。
五、迁移脚本要尽量可重复检查
有些脚本可以写得更安全。
比如 PostgreSQL 里:
1 | CREATE TABLE IF NOT EXISTS users ( |
加索引:
1 | CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); |
但也不要过度依赖 IF NOT EXISTS。
如果表已经存在但结构不对,IF NOT EXISTS 可能会掩盖问题。
所以迁移脚本最好由工具保证只执行一次,而不是每条 SQL 都写成“随便重复执行也没事”。
六、危险变更要拆步骤
最危险的迁移通常是:
- 删除字段
- 改字段类型
- 改字段含义
- 加 NOT NULL
- 大表加索引
- 大表更新全量数据
不要一次性写:
1 | ALTER TABLE users DROP COLUMN old_name; |
更稳的方式是分阶段:
1 | 1. 新增 new_name 字段 |
这叫兼容式迁移。
它比“一刀切”麻烦,但生产环境安全很多。
七、大表变更要考虑锁
小表怎么改都不明显。
大表不一样。
比如千万级数据表上加字段、加索引、改类型,都可能导致锁表或长事务。
上线前至少要问:
- 这条 DDL 会不会锁表?
- 需要多久?
- 有没有并发写入影响?
- 能不能在线创建索引?
- 是否需要分批回填?
- 是否需要低峰期执行?
例如 PostgreSQL 创建索引可以考虑:
1 | CREATE INDEX CONCURRENTLY idx_orders_user_id ON orders(user_id); |
不同数据库细节不一样。
但原则一样:大表迁移要先评估,不要在发布脚本里盲跑。
八、数据回填不要塞进一个巨大事务
假设要给历史用户回填状态:
1 | UPDATE users SET status = 'active' WHERE status IS NULL; |
如果表很大,这条 SQL 可能执行很久,产生大量锁和 WAL/binlog。
更稳的方式是分批:
1 | UPDATE users |
应用层或脚本按 ID 范围循环执行。
每批提交一次。
这样失败后也更容易恢复。
迁移不是越自动越好。
关键是可控。
九、回滚脚本要谨慎
有些迁移工具支持 down 脚本。
比如:
1 | -- up |
看起来很美。
但生产环境里,回滚数据库不总是安全的。
如果新字段已经写入数据,直接 drop 就会丢数据。
所以我更倾向:
1 | 代码可以快速回滚 |
也就是说,down 脚本可以有,但不要把它当万能撤销按钮。
十、迁移要纳入发布流程
推荐发布顺序:
1 | 1. 备份关键数据 |
很多时候,数据库迁移不应该和应用部署强绑定在同一分钟。
尤其是大表迁移和数据回填,最好拆成独立步骤。
发布越复杂,越需要清单。
不要靠临场发挥。
十一、我的建议
数据库迁移可以先从几个简单规则开始:
- 所有结构变更都写迁移脚本
- 迁移脚本进 Git
- 禁止手工改生产结构后不补脚本
- 用迁移工具记录执行版本
- 危险变更拆成兼容步骤
- 大表变更先评估锁和耗时
- 数据回填分批执行
- 回滚脚本不要盲目自动跑
- 发布前在测试库完整演练一次
数据库迁移不是为了形式感。
它是为了让每一次结构变化都可追踪、可复现、可恢复。
项目越久,这件事越值钱。