数据库三大范式设计详解

数据库三大范式设计详解

什么是范式

数据库范式(Normalization)是关系数据库设计中的一套理论规范,目的是减少数据冗余、避免更新异常、保证数据完整性。范式级别越高,表结构拆分得越细,数据的冗余度越低。

第一范式(1NF):列不可再分

核心要求:表中的每一列都是不可再分的最小原子单元。

违反 1NF 的例子

学生表学号姓名联系方式

学号 | 姓名 | 联系方式
1001 | 张三 | 13800138000, zhangsan@email.com
1002 | 李四 | 13900139000, lisi@email.com

“联系方式”列包含电话和邮箱两个独立信息,违反了 1NF。

符合 1NF 的修正

学生表学号姓名电话邮箱

学号 | 姓名 | 电话 | 邮箱
1001 | 张三 | 13800138000 | zhangsan@email.com
1002 | 李四 | 13900139000 | lisi@email.com

每个单元格只存一个不可拆分的数据项。

注意:1NF 在实践中

MySQL 的 JSON 类型看似违反 1NF(一个列里存了多个字段),但这是因为 MySQL 将 JSON 当作一个原子数据类型来处理,应用层通过 JSON 函数访问内部字段,所以不视为违反 1NF。

第二范式(2NF):完全依赖主键

核心要求:满足 1NF 的基础上,表中的非主键列必须完全依赖于主键,不能只依赖主键的一部分(即消除部分依赖)。

违反 2NF 的例子

订单明细表(订单ID,商品ID,商品名称,数量,单价)

主键:(订单ID,商品ID)联合主键

问题:商品名称只依赖于商品ID,不依赖于(订单ID, 商品ID)联合主键

符合 2NF 的修正

订单明细表(订单ID,商品ID,数量,单价)
主键:(订单ID, 商品ID)

商品表(商品ID,商品名称,单价)
主键:商品ID

将依赖主键部分的字段拆分到新表,消除部分依赖。

2NF 的适用范围

  • 只有联合主键的表才可能出现违反 2NF 的问题
  • 单字段主键的表天然满足 2NF

第三范式(3NF):不依赖非主键列

核心要求:满足 2NF 的基础上,非主键列不能传递依赖于其他非主键列。

违反 3NF 的例子

员工表(员工ID,姓名,部门编号,部门名称,部门地址)

问题:部门名称和部门地址依赖于部门编号,而部门编号依赖于员工ID
→ 传递依赖:员工ID → 部门编号 → 部门名称

符合 3NF 的修正

员工表(员工ID,姓名,部门编号)

部门表(部门编号,部门名称,部门地址)

3NF 的本质

3NF 消除的是”非主键列之间的依赖关系”。如果 A 列和 B 列之间存在确定的映射关系,就应该拆分到另一个表中去。

范式总结表格

范式 核心要求 消除的问题
1NF 列不可再分 列数据不原子
2NF 完全依赖主键 部分依赖
3NF 不依赖非主键 传递依赖

范式的实际意义

遵循三大范式带来的好处:
1. 减少数据冗余:同样数据只存一份,节省存储
2. 避免更新异常:如果”商品名称”只存一处,改名只需改一个地方
3. 避免插入异常:没有订单也能先录入商品信息
4. 避免删除异常:删除订单不会误删商品信息

范式的局限性

过度范式化也不是好事:
– 查询时 JOIN 过多,性能下降
– 某些场景下适量的冗余反而更好(这就是反范式化)
– 高并发读场景下,冗余可以减少 JOIN 次数

面试常问题

Q:数据库范式一定是越高越好吗?
A:不一定。实际项目中通常是 3NF + 少量反范式的折中方案。3NF 能保证数据的完整性,反范式则用于提升特定查询的性能。面试时不要一棍子打死说”必须 3NF”。

Q:设计表时怎么快速判断几范式?
A:看主键(唯一主键→至少 2NF),看有没有重复存储的冗余列→可能是违反 3NF 的传递依赖。

Q:BCNF 和 3NF 有什么不同?
A:BCNF(Boyce-Codd 范式)是 3NF 的加强版。当表中有多个候选键且这些键有重叠时,3NF 可能仍有冗余,BCNF 则要求每个决定因素都是候选键。实际工程中极少用到 BCNF。

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容