回答“数据库已经承载生产状态以后,表结构、历史数据、服务边界和迁移路径怎样继续安全变化”
| 常见表象 | 更可能的根因 | 为什么它是数据库演进问题 |
|---|---|---|
| 应用回滚了,但数据回不去 | 变更没有区分应用可逆和数据不可逆 | 数据库状态一旦被写入,回滚模型就不同于代码 |
| 一个字段想删,查不清谁还在用 | 字段依赖面没有观测,弃用流程缺失 | 清理旧结构前必须知道真实消费面 |
| 服务拆出来了,但还共享同一批表 | 数据 ownership 没有随服务边界一起演进 | 共享数据库会把服务边界重新粘回去 |
| 回填脚本跑到一半失败,没人敢重跑 | 迁移动作不可幂等、不可恢复、不可观测 | 生产迁移必须像系统一样设计,而不是像一次性脚本 |
| 历史报表和新业务口径长期对不上 | 历史数据迁移、口径切换和校验退场没有闭环 | 数据库演进不只改当下结构,也会改变历史解释 |
| 动作 | 风险 | 推荐方式 | 不要怎么做 |
|---|---|---|---|
| 新增字段 | 默认值、旧服务读取、新服务写入顺序 | 先加 nullable 或安全默认值,再让应用逐步写入 | 一次上线同时加字段、强依赖、删旧逻辑 |
| 删除字段 | 仍有长尾消费者读取 | 先观测使用面,标记弃用,确认清零后删除 | 只搜代码仓库就认为没人用 |
| 重命名字段 | 本质上通常是新增加删除 | 新旧字段并存,双写,迁移读路径,再清理旧字段 | 直接 rename column 期待所有版本同时升级 |
| 拆表 / 合表 | 查询路径、事务边界和历史数据都变 | 先建立新模型,回填,双写,影子校验,再切读 | 把 schema 变更和业务切换压成一次大上线 |
| 索引调整 | 建索引锁表、写放大、执行计划变化 | 在线 DDL、低峰执行、观测慢查询和写入延迟 | 只看读查询收益,不看写入成本 |
| 主数据迁移 | 谁是事实源说不清,双写不一致 | 明确 source of truth,设计双写/校验/切换/退场阶段 | 两个系统长期都自称主数据 |
| 变更类型 | 回滚特点 | 更稳的设计 |
|---|---|---|
| 只加字段且旧应用忽略 | 通常较容易回滚应用 | 让 schema 先行,应用慢慢使用 |
| 写入新字段但旧字段仍保留 | 可以回到旧读路径,但要处理数据差异 | 双写期间持续校验,准备补偿任务 |
| 删除字段 / 表 | 通常不可直接回滚 | 先长时间弃用和归档,再删除 |
| 全量历史数据重算 | 回滚成本高,且可能影响报表和下游 | 保留旧口径快照,分批切换,按租户或时间段验证 |
| 主数据源切换 | 回滚涉及事实源和写入冲突 | 切换前定义冻结窗口、冲突策略和恢复手册 |
真正危险的迁移通常跨应用、发布、数据口径、读写路径和业务 owner,不是单个 SQL 能解决的。
很多数据库变更一旦写入新状态,应用回滚只解决代码问题,不解决状态问题。
双写只是过渡手段,还必须有幂等、顺序、失败补偿、差异校验和退场计划。
旧字段、旧表、旧任务、旧报表和旧消费者没有退场,迁移就还在继续消耗组织注意力。
数据库演进最容易被低估的工作,常常不是“怎么切过去”,而是“怎么确认旧世界真的可以退出”。
| 如果你正在处理什么问题 | 建议配套页 | 为什么连着看 |
|---|---|---|
| 想先建立数据库分类、存储、事务和高可用底层认知 | 数据库 | 数据库演进建立在基本数据库能力之上,而不是替代数据库基础 |
| 想把 schema 演进、回填和重放放进数据生产线 | 数据工程 | 很多数据库演进会继续影响下游数仓、报表、补数和数据质量 |
| 想把数据库迁移接回应用发布和灰度回滚 | 发布工程 | 数据库变更必须和应用版本、开关、灰度、回滚模型一起设计 |
| 想看后端系统里数据正确性和变更治理 | 后端工程 | 后端工程负责把数据层演进放回接口、事务、缓存、消息和交付链路 |
| 想看契约和字段语义怎样保护演进 | 数据契约 | 数据库结构变化最终要通过 API、事件和数据流契约传递给消费者 |
| 想看数据系统为什么必须考虑长期演进 | 《DDIA》 | DDIA 提供编码与演进、日志、回放、重算和衍生数据的底层视角 |
| 想把共享数据库从单体迁移到服务边界 | 《从单体到微服务》 | 服务化迁移里最硬的部分,往往就是数据 ownership 和共享库退场 |