梳理一下 MySQL(或关系型数据库)中的第一、二、三、四范式,这是数据库设计中非常重要的规范化理论。
1️⃣ 第一范式 (1NF:First Normal Form)
定义:字段具有原子性,不可再分。
数据表中每一列都必须是不可分割的最小数据单元。
每一行都应该是唯一的(通常通过主键来保证)。
✅ 举例:
不符合 1NF:
学生表
学号 姓名 联系方式
1 张三 1380000, 1391111
问题:联系方式有多个值,违反原子性。
符合 1NF:
学生表
学号 姓名 联系方式
1 张三 1380000
1 张三 1391111
2️⃣ 第二范式 (2NF:Second Normal Form)
定义:在 1NF 的基础上,要求每个非主属性完全依赖于主键,不能只依赖主键的一部分。
适用于 联合主键 的情况。
消除部分依赖。
✅ 举例:
不符合 2NF:
选课表
学号+课程号 (联合主键) 姓名 成绩
1+001 张三 95
问题:姓名只依赖学号,而不是依赖于 (学号+课程号) 这个整体主键。
符合 2NF(拆表):
学生表
学号 姓名选课表
学号 课程号 成绩
3️⃣ 第三范式 (3NF:Third Normal Form)
定义:在 2NF 基础上,非主属性不依赖于其他非主属性(消除传递依赖)。
属性不能依赖于主键之外的属性。
✅ 举例:
不符合 3NF:
学生表
学号 姓名 系编号 系名称
问题:系名称依赖于系编号,而系编号又依赖学号(学号 → 系编号 → 系名称,产生传递依赖)。
符合 3NF(拆表):
学生表
学号 姓名 系编号系别表
系编号 系名称
4️⃣ 第四范式 (4NF:Fourth Normal Form)
定义:在 3NF 基础上,要求多值依赖消除。
一张表中不应包含两个或多个相互独立的多对多关系。
✅ 举例:
不符合 4NF:
学生表
学号 爱好 擅长课程
1 足球 数学
1 足球 英语
1 篮球 数学
1 篮球 英语
问题:爱好与擅长课程之间是独立的多值依赖,导致大量冗余。
符合 4NF(拆表):
学生_爱好表
学号 爱好学生_课程表
学号 擅长课程
🔑 总结
1NF:字段不可再分(原子性)
2NF:非主属性完全依赖主键(消除部分依赖)
3NF:非主属性不依赖于其他非主属性(消除传递依赖)
4NF:不允许一个表里有多个独立的多值依赖
👉 实际开发中:
3NF 已经能满足大部分场景;
4NF 更偏学术,业务里一般用到 3NF + 适当的反规范化(为了性能)。
👌 那我帮你整理一个 1NF ~ 4NF 对比表,方便快速理解和记忆:
📊 数据库范式对比表
范式 | 要求 | 典型问题 | 示例(不符合) | 示例(符合) |
---|---|---|---|---|
第一范式 (1NF) | 字段必须原子化,不可再分 | 字段中有多个值,违反原子性 | 联系方式: 1380000, 1391111 | 每条记录一条联系方式 |
第二范式 (2NF) | 在 1NF 基础上,非主属性必须完全依赖主键,不能部分依赖 | 联合主键时,非主属性只依赖其中一部分 | (学号+课程号) → 姓名 | 将姓名拆到“学生表” |
第三范式 (3NF) | 在 2NF 基础上,非主属性不能依赖其他非主属性(消除传递依赖) | 非主属性依赖另一个非主属性 | 学号 → 系编号 → 系名称 | 把“系编号-系名称”拆到“系别表” |
第四范式 (4NF) | 在 3NF 基础上,消除多值依赖(不能同时描述多个独立的多对多关系) | 一张表里既存储“爱好”,又存储“擅长课程” | 学号 → 爱好 和 学号 → 擅长课程 | 分成“学生_爱好表”和“学生_课程表” |
📌 记忆口诀:
1NF:字段原子化
2NF:消除部分依赖
3NF:消除传递依赖
4NF:消除多值依赖
画一个 范式演进示意图(从 1NF → 4NF,逐步拆表的过程)这样更直观。
画一个 1NF → 4NF 的演进示意图,用一个「学生」场景,逐步展示规范化的过程:
📝 范式演进示意图
❌ 未规范化
学生表
学号 | 姓名 | 联系方式 | 系名称 | 爱好 | 擅长课程
1 | 张三 | 1380000,1391111 | 计算机系 | 足球 | 数学
问题:
联系方式不原子化(违反 1NF)
姓名只依赖学号,不依赖课程号(违反 2NF)
系名称依赖于系编号,而不是直接依赖学号(违反 3NF)
爱好和课程是独立的多值依赖(违反 4NF)
✅ 第一范式 (1NF)
解决字段不可再分 → 拆分联系方式
学生表
学号 | 姓名 | 联系方式 | 系编号 | 系名称 | 爱好 | 擅长课程
1 | 张三 | 1380000 | 01 | 计算机 | 足球 | 数学
1 | 张三 | 1391111 | 01 | 计算机 | 足球 | 数学
✅ 第二范式 (2NF)
解决部分依赖 → 拆分“学生”和“选课”
学生表
学号 | 姓名 | 系编号选课表
学号 | 课程号 | 成绩
✅ 第三范式 (3NF)
解决传递依赖 → 把系名称单独拆表
学生表
学号 | 姓名 | 系编号系别表
系编号 | 系名称选课表
学号 | 课程号 | 成绩
✅ 第四范式 (4NF)
解决多值依赖 → 爱好、擅长课程单独拆表
学生表
学号 | 姓名 | 系编号系别表
系编号 | 系名称选课表
学号 | 课程号 | 成绩学生_爱好表
学号 | 爱好学生_课程表
学号 | 擅长课程
📌 最终结果:
每张表结构更清晰,避免冗余和异常(插入、更新、删除异常)。
实际项目中常用到 3NF,4NF 更多是学术或复杂业务场景。