欢迎光临
我们一直在努力

Codex给数据库字段加了默认值,为什么旧数据还是NULL?

使用 ChatGPT、Codex 修改数据库 Schema、实体类或者 Migration 时,经常会遇到一种很典型的问题:

明明已经给字段加了默认值,新数据也正常,为什么数据库里的旧记录还是一堆 NULL?

常见表现包括:

  • 新增字段以后设置了默认值;
  • 新插入的数据都有值;
  • 历史数据却完全没变化;
  • ORM实体类里已经写了默认值;
  • Migration也执行成功;
  • 页面上新记录正常,老记录却不断触发空值判断;
  • Codex检查代码时看起来没有任何问题。

这类问题的核心不是:

默认值没有生效。

而是:

“默认值影响新写入”和“给历史数据补值”本来就是两件事。


一、数据库Default通常只负责“以后怎么写”

假设给用户表新增一个字段:

status

默认值是:

active

很多人会自然理解成:

加完默认值以后,原来所有NULL都会自动变成active。

但数据库里的 Default 更常见的作用其实是:

以后插入新记录时,如果没有主动提供这个字段,就自动使用默认值。

它解决的是:

未来的数据写入。

而不是自动重写:

过去已经存在的数据。


二、为什么新数据正常,旧数据却完全不变?

例如表里原来已经有100万条历史记录。

现在新增:

status DEFAULT 'active'

之后新建用户时:

如果没有传status,数据库可以自动填:

active

但历史100万条数据是否会被补值,要看:

  • 数据库类型;
  • Migration具体写法;
  • 字段是否允许NULL;
  • 是否执行了Backfill。

不能只看到:

Default已经存在

就认为:

历史数据也已经迁移完成。


三、应用层默认值和数据库默认值也不是一回事

有时候 ChatGPT、Codex 会在实体类里写:

status = "active"

这属于:

应用层默认值。

意思是:

通过当前应用创建对象时,status默认是active。

但如果数据来自:

  • SQL脚本;
  • 其他服务;
  • 数据导入;
  • 后台任务;
  • 旧版本程序;

就不一定经过这层默认逻辑。

所以系统里可能同时存在:

ORM默认值

数据库Default

两套机制。

最好明确谁才是最终数据边界。


四、NULL和默认值的业务含义也要先想清楚

有些项目一看到NULL,就想全部改成默认值。

但这并不一定总是正确。

例如:

approved_at = NULL

可能表示:

还没有审批。

如果简单补成某个默认时间,反而破坏业务语义。

所以真正需要先确认的是:

NULL到底代表“缺失”,还是代表一种真实状态?

只有确定:

历史NULL本来就应该等价于默认值

才适合批量补齐。


五、历史数据需要单独做Backfill

如果确认老数据应该补成默认值,就需要单独考虑:

历史数据回填。

也就是Backfill。

例如逻辑上可能是:

将所有status为NULL的历史记录更新为active。

这一步和:

给字段设置Default

应该分开理解。

一个负责:

修历史。

一个负责:

管未来。

很多Migration的问题,就是只做了第二件事,没有做第一件事。


六、大表Backfill不能随便一次全改

如果表只有几千条记录,问题可能不大。

但如果有几百万、上千万条数据,一次性更新全部NULL记录,可能带来:

  • 长事务;
  • 锁等待;
  • IO压力;
  • 主从延迟;
  • 线上查询变慢。

所以历史数据回填也要考虑:

数据量和执行方式。

很多时候更稳的是:

分批更新 + 观察影响 + 最终校验。

不能因为只是“补一个默认值”,就低估Migration风险。


七、字段允许NULL时,Default也挡不住主动写NULL

这是非常容易误解的一点。

即使数据库定义:

DEFAULT 'active'

如果应用明确写入:

NULL

数据库仍然可能保存NULL。

因为Default通常在:

字段没有提供值

时生效。

而不是:

字段明确传了NULL

时强制替换。

所以如果业务上真的不允许NULL,还需要继续考虑:

NOT NULL约束。


八、Migration成功不代表数据迁移完成

很多人看到:

Migration completed successfully.

就认为任务已经完成。

但Migration成功只说明:

SQL执行成功。

还应该继续验证:

  • 字段是否真的有Default;
  • 历史NULL数量还有多少;
  • 新写入是否符合预期;
  • 应用层有没有继续主动写NULL;
  • 老数据回填是否完整。

如果不做这些检查,就很容易出现:

结构改完了,数据状态却没改完。


九、最好把字段改造拆成几个步骤

比较稳的思路是:

第一步:明确NULL和默认值的业务含义。

确认历史数据到底应该是什么。

第二步:新增字段或Default。

保证新数据有明确规则。

第三步:回填历史数据。

必要时分批处理。

第四步:增加NOT NULL等约束。

如果业务确实不允许NULL。

第五步:验证新旧数据一致性。

确认系统不会继续产生新的NULL。

这样比“一条Migration全做完”更容易控制风险。


十、可以直接这样让ChatGPT、Codex检查

以后遇到这类问题,可以直接要求:

请不要只检查字段Default是否已经设置。先确认这个默认值只影响新写入,还是历史数据也需要单独Backfill;检查ORM默认值和数据库Default是否一致,并确认应用是否会主动写NULL。如果业务不允许NULL,再评估NOT NULL约束。对于大表历史数据,请给出分批回填和最终校验方案,不要只以Migration执行成功作为完成标准。

这样比简单说:

给这个字段加个默认值。

更完整。


最后

Codex给数据库字段加了默认值以后,旧数据还是NULL,真正的问题通常不是:

Default失效。

而是:

默认值解决的是未来数据,而历史数据需要单独迁移。

稳定的数据改造应该区分:

Default → 管未来写入

Backfill → 修历史数据

NOT NULL → 守最终约束

所以以后看到:

新数据都有值,旧数据还是NULL。

第一反应不要继续改Default。

更应该先问:

这些历史NULL到底有没有做过真正的数据回填?


持续更新 ChatGPT、Codex、AI编程与后端工程实战内容,更多深度内容和稳定订阅渠道欢迎搜索关注「孤狼GPT」。

赞(0)
未经允许不得转载:171主机测评 » Codex给数据库字段加了默认值,为什么旧数据还是NULL?
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址