全书目录

第十八篇:MySQL 完全指南 —— 城市户籍总账宇宙

第十二章:范式基础 —— 别把整座城市抄进一行

1 分钟 442 字 第 347 / 962 个阅读单元

范式听起来很学院派,但本质很朴素:

避免重复、歧义和更新异常。

先看一种糟糕设计:

text
household_book
------------------------------------------------------------
household_no | district_name | address |
citizen1_name | citizen1_birth |
citizen2_name | citizen2_birth |
citizen3_name | citizen3_birth

这张表的问题一眼可见:

  • 一户如果有 4 个人怎么办
  • 市民栏目重复
  • 删除一个人可能把整户信息搞乱
  • 改区名要改很多行
  • 查询“所有市民”也很难写

所以需要范式思维。

第一范式 1NF:一格一值,不要在一个字段里塞列表或重复组

错误:

text
citizen_names = '林远,周宁,陈舟'

正确:一人一行。

第二范式 2NF:如果主键是组合键,非主属性要依赖整个键,而不是只依赖一部分

这在中间表里最容易出问题。比如:

text
citizen_programs(citizen_id, program_id, citizen_name)

如果 citizen_name 只依赖 citizen_id,就不该放这里。

第三范式 3NF:非主属性不要再依赖另一个非主属性

例如在 citizens 表里反复存:

text
citizen_id, household_id, district_name

district_name 其实可以通过 households -> districts 推出来,这就是冗余。

规范拆分后更像这样:

text
districts   -> 区信息
households  -> 户信息
citizens    -> 人信息
move_logs   -> 迁移流水

要点不是“逢表必拆”,而是:

先把稳定实体拆清楚,再谨慎引入冗余。

范式解决的是“先别把账做乱”;性能优化解决的是“账正了以后怎么翻更快”。