先给结论:不要急着改数据库表结构,而是先判断新增字段属于“补充属性”还是“新的业务对象”。前者可以用扩展字段表或JSON列过渡,后者必须建新表并迁移关系。判断依据是你手头那份字段清单里,有多少条记录会在新字段上填值——如果只有个别样本填得满,而规模化后大量记录留空,说明字段设计本身需要重新分层,而不是简单加列。
假设你手上有50条已上线的用户提交记录,现在业务要求增加“所属行业细分”“对接人职务”“历史合作次数”三个字段。先做一件事:把这50条记录逐条对照新字段,标记哪些能填、哪些填不了。
这个动作的结果直接决定下一步:能填满的走加字段路线,填不满的走拆分对象路线,一对多的走建表路线。三种路线的迁移成本和回滚难度完全不同。
扩展字段表(一张表存对象ID、字段名、字段值)常被当作万能方案,但它有明确的适用条件:新增字段数量少、查询频率低、不需要用这些字段做筛选和排序。满足这三条时,扩展表可以让你在不改主表的前提下快速上线。
反噬出现在规模化之后。假设你用扩展表存了“对接人职务”,起初只有几十条记录,查询靠应用层拼装没问题。当记录涨到几万条,并且运营要求“按职务筛选用户列表”时,扩展表的查询会变成多次关联或全表扫描,性能下降。这时正确的动作是:把高频筛选字段从扩展表迁回主表或独立维表,而不是继续在扩展表上建索引硬扛。
判断信号很简单:如果某个扩展字段开始出现在列表页的筛选条件里,它就不该留在扩展表。这个判断不需要等性能报警,在需求评审阶段就能识别。
另一种常见做法是在主表加一个JSON列,把新字段先塞进去。它的好处是不改表结构就能写入,适合字段还在频繁变动的阶段。但它不能替代正式字段设计,因为JSON列里的值默认没有类型约束,查询和统计也依赖数据库对JSON的支持程度。
假设你用JSON列存“历史合作次数”,初期只用来展示。后来业务要按合作次数分档发权益,这时如果继续在JSON里取值比较,不同数据库的写法不一致,维护成本会上升。合理的触发条件是:当一个JSON字段被两个以上业务模块读取,或者需要参与排序、分组、聚合时,就把它提升为正式列。
这个动作的结果是:你保留了JSON列作为临时缓冲区,但每个字段都有明确的“转正”标准,避免JSON列无限膨胀成事实上的主表。
字段设计想清楚之后,落地顺序决定你会不会丢数据或长时间停机。可执行的顺序是:
其中第三步的回填失败条目是关键证据。如果失败集中在某几类记录上,说明这些记录本身不符合新字段的假设,需要先修数据模型,而不是强行回填。这个结果会直接影响你是否能进入第四步。
假设你的网站是乌鲁木齐本地一家服务商的预约提交页,最初只收集姓名、电话、需求描述。上线三个月后有50条记录,你想增加“预算区间”和“期望上门时间”。在50条样本上,这两个字段都能从需求描述里人工判断出来,看起来加两列就够了。
但当记录涨到5000条时,你会发现“期望上门时间”有大量记录填的是模糊描述,无法直接用于排期;而“预算区间”在不同服务类型下含义不同,同一个区间值在A服务里代表低预算,在B服务里代表正常预算。这时正确的扩展方式不是继续加列,而是把“服务类型”作为前置字段,再按服务类型分别定义预算和时间字段的取值范围。
这个例子的意义在于:个别样本成立不等于规模化后成立。判断字段是否够用,要看你能否说清每个字段在不同业务分支下的取值规则,而不是看当前记录能不能填上。
回到你手上的那份字段清单:先标出哪些字段在规模化后会出现大量空值或语义分歧,再决定是加列、建扩展表还是拆新对象。这个判断做完之后,迁移顺序才有意义。