先判断一件事:现有字段是“不够用”还是“用错了”。如果只是缺少几个可选字段,保留现有结构、做向后兼容的扩展通常代价最低;如果核心实体关系已经错位,比如把本该独立成表的对象塞进一个文本字段,那么继续加字段只会让后续查询和维护越来越难,此时应把改写甚至局部重建列入选项。无论选哪条路,第一步都不是改数据库,而是先导出当前表结构与全部历史数据,确认哪些字段有值、哪些值为空、哪些值格式不统一——这个动作的结果直接决定你是能平滑扩展,还是必须先做数据清洗。
当新增需求只是“多记录几个属性”,而现有记录之间的从属关系没变时,保留原表、追加字段是合理选择。典型前提是:旧字段仍能被新逻辑使用,新字段允许为空,且没有字段需要拆成多值。
具体动作可以这样安排:先加可空字段,不设默认值也不加非空约束;写入端先只在新流程里填,旧流程保持不变;观察一段时间后再决定是否回填历史数据。这样做的结果是,线上写入不会被新约束打断,你可以随时回退。需要提醒的是,加字段后页面能正常显示,并不能证明旧数据已经完整——空值可能来自“本来就没有”,也可能来自“迁移时漏了”,这两者必须靠抽样比对区分。
如果字段名没变,但含义已经改变,直接复用会制造隐性错误。例如原来一个 contact 字段只存手机号,现在要同时存手机号和邮箱,这时它不是“加一个字段”的问题,而是“一个字段承担两种语义”的问题。
两种处理成立的条件不同:
判断依据不是字段名,而是查询语句:搜索代码里还有多少处按旧语义读取它。如果这类读取点很多,原地改写的风险会成倍上升。
出现下面这些信号时,继续在旧结构上打补丁往往得不偿失:同一实体被拆散在多个文本字段里、需要按子项检索却只能模糊匹配、每次新增需求都要改动多处写入逻辑。此时可考虑新建一张表或一套结构,把旧数据迁移过去,旧结构保留只读一段时间。
重建并不等于推翻整站。更常见的做法是只重建出问题的那部分数据模型,页面和接口逐步切换。假设某站把“服务项目”和“服务区域”都塞进一个备注字段,后来要按区域筛选,那么新建两张关联表、迁移后再让筛选走新表,比在原字段上做字符串匹配更可控。这里的数字只用于说明比较方法:如果旧数据里同一区域存在三种以上写法,靠匹配扩展的成功率就会明显下降。
如果你拿不到完整历史数据,或者没有直接改表结构的权限,仍有一个最小动作:先整理一份字段清单,标注每个字段的用途、是否必填、是否有值、由哪个页面写入。这份清单可以只靠现有页面和接口响应反推,不需要数据库权限。
它的直接结果是:你能明确区分“必须现在就加”的字段和“可以等权限到位再处理”的字段,从而避免在信息不全时做出不可逆的结构改动。但要注意,页面看不到某字段,不代表数据库里没有;接口没返回,也不代表它没被使用。因此这份清单只能支撑“先加可空字段”这类低风险动作,不能用来断定旧字段可以安全删除。
一个可执行的顺序是:先导出结构与样本数据,再统计每个字段的实际使用点,然后按“追加可空字段—新增独立字段—重建局部结构”由轻到重选择。每完成一步,都用同一批样本数据回查一次,确认新写入和旧数据都能被正确读出。如果回查发现旧记录读不出来,说明兼容层还没做好,此时不应继续推进更重的改动。
扩展字段的本质不是把表改大,而是让新旧两种写入方式在一段时间内共存,直到你确认可以安全收口。