数据库范式

  • 数据库范式,本质上是一套“数据整理的物理学定律”。它不关心你业务多酷炫,只关心一件事:如何让数据结构更干净、更一致、更少冗余

第一范式(1NF)

*字段必须是原子值(不可再分)

比如你建一个学生表:

学号 姓名 电话
1 张三 123,456

电话存两个号码违反1NF,因为一个字段里放了多个值。

正确做法要么拆成:

学号 姓名 电话
1 张三 123
1 张三 456

要么单独建电话表。


第二范式(2NF)

核心思想:消除部分依赖
如果一个表的主键是“联合主键”,那么非主键字段必须依赖整个主键,而不是只依赖一部分。

举个例子:

| 学号 | 课程号 | 学生姓名 | 课程名称 | 成绩 |

主键是(学号 + 课程号)。

问题来了:

  • 学生姓名只依赖“学号”
  • 课程名称只依赖“课程号”

这叫部分依赖

结果就是:同一个学生选 10 门课,姓名重复 10 次。

解决方法:拆表。

学生表
课程表
选课表

2NF解决的是“局部重复”问题。


第三范式(3NF)

核心思想:消除传递依赖

传递依赖是这样:

A → B
B → C
那 A → C 就是传递依赖。

举例:

| 学号 | 姓名 | 系号 | 系名称 |

  • 学号 → 系号
  • 系号 → 系名称

于是:学号 → 系名称(传递)

问题:系名称被重复存储。

解决方法:再拆:

学生表(学号,姓名,系号)
系表(系号,系名称)

3NF解决的是“间接重复”。


面试角度总结(Java 后端常考)

  1. 范式的目的是什么?

    • 减少冗余
    • 避免更新异常
    • 提高数据一致性
  2. 1NF、2NF、3NF区别?

    • 1NF:字段必须是原子值;不能一个字段存多个值。解决的是“数据格式混乱”。
    • 2NF:消除部分依赖;非主键字段必须完全依赖整个主键。解决的是“局部重复”。
    • 3NF:消除传递依赖;非主键字段不能依赖另一个非主键字段。解决的是“间接重复”。
    • 记忆逻辑可以这样理解:
      • 1NF 管格式
      • 2NF 管主键依赖
      • 3NF 管非主键之间的依赖
  3. 为什么实际项目不完全遵守?

    • 性能考虑
    • 业务复杂度
    • 维护成本