数据库迁移指南
迁移工具对比
| 工具 | 语言 | 方式 | 最适合 |
|---|---|---|---|
| Flyway | Java/CLI | 版本化 SQL 文件(V1__name.sql) | Java 应用、SQL 优先团队 |
| Liquibase | Java/CLI | XML/YAML/SQL 变更日志 | 多数据库、复杂变更集 |
| golang-migrate | Go/CLI | 编号 .up.sql / .down.sql | Go 应用、简单 SQL 迁移 |
| Alembic | Python | 含 upgrade/downgrade 的 Python 脚本 | SQLAlchemy/Python 项目 |
| Prisma Migrate | TypeScript | 基于 Schema Diff 自动生成 | Node.js/TypeScript 应用 |
| Atlas | Go/CLI | 声明式(目标状态)或版本化 | 现代 Go 应用、CI/CD |
零停机:扩展-收缩模式
-- 场景:将列 "username" 重命名为 "display_name"
-- 不能直接执行(会立刻导致线上故障):
-- ALTER TABLE users RENAME COLUMN username TO display_name;
-- 第一步(扩展):新增列,保留旧列
ALTER TABLE users ADD COLUMN display_name VARCHAR(100);
-- 第二步:回填新列数据
UPDATE users SET display_name = username WHERE display_name IS NULL;
-- 第三步:部署同时写入两列的新代码
-- 第四步:确认新代码已全量部署
-- 第五步(收缩):删除旧列
ALTER TABLE users DROP COLUMN username;
-- 零停机索引创建(PostgreSQL)
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);
-- CONCURRENTLY 不阻塞写入,但耗时更长
迁移执行清单
| 阶段 | 操作 |
|---|---|
| 迁移前 | 全量备份数据库 |
| 迁移前 | 在 staging 环境用生产数据副本测试 |
| 迁移前 | 评估 DDL 变更的锁持有时长 |
| 迁移前 | 准备回滚脚本并验证可用性 |
| 迁移中 | 监控活跃连接数和主从延迟 |
| 迁移中 | 设置 statement_timeout 避免无限等锁 |
| 迁移后 | 验证行数和数据完整性 |
| 迁移后 | 监控慢查询和索引使用情况 |
| 收尾 | 确认旧代码完全下线后再删废弃列 |