数据库设计范式详解
一、什么是数据库范式?
Section titled “一、什么是数据库范式?”范式是数据库设计的规则,目的是让数据结构更合理,避免以下问题:
- 数据冗余(同一份数据重复存储)
- 更新异常(修改数据时可能遗漏某些地方)
- 插入/删除异常(操作数据时可能破坏完整性)
二、从第一范式到第四范式
Section titled “二、从第一范式到第四范式”范式的划分是逐层递进的,每个范式都建立在满足前一个范式的基础上。
1. 第一范式(1NF)
Section titled “1. 第一范式(1NF)”含义:是最基本的范式,它要求数据库表的每一列都是不可分割的原子数据项,不能是列表、数组等多值数据。
目标:消除重复字段,确保每列不可再分。
示例:
×:学生表中有一个字段 课程 存储 [“数学”,“英语”](多值)。
√:拆分为两行,每行存储一门课程:
| 学生ID | 课程 |
|---|---|
| 1001 | 数学 |
| 1001 | 英语 |
2. 第二范式(2NF)
Section titled “2. 第二范式(2NF)”含义:在满足1NF的基础上,消除部分依赖(非主属性必须完全依赖主键)。
目标:解决“一个表有多个主键”导致的冗余问题。
示例:
×:订单表(订单ID和产品ID联合主键)中直接存储产品名称:
| 订单ID | 产品ID | 产品名称 |
|---|---|---|
| 1001 | P001 | 手机 |
| 1002 | P001 | 手机 |
PS:产品名称在订单表中是冗余的,因为订单表中已经存储了产品ID,通过产品ID可以直接查询到产品名称。
√:拆分为两张表:
订单表(主键:订单ID):
| 订单ID | 产品ID |
|---|---|
| 1001 | P001 |
| 1002 | P001 |
产品表(主键:产品ID):
| 产品ID | 产品名称 |
|---|---|
| P001 | 手机 |
3. 第三范式(3NF)
Section titled “3. 第三范式(3NF)”含义:在满足2NF的基础上,消除传递依赖(非主属性不能依赖其他非主属性)。
目标:解决“通过非主属性间接依赖主键”导致的冗余问题。
示例:
×:学生表中存储所属学院和学院电话:
| 学生ID | 姓名 | 所属学院 | 学院电话 |
|---|---|---|---|
| 1001 | 张三 | 信息学院 | 010-12345678 |
PS:学院电话依赖所属学院,而所属学院依赖学生ID(传递依赖)。
√:拆分为两张表:
学生表(主键:学生ID):
| 学生ID | 姓名 | 所属学院 |
|---|---|---|
| 1001 | 张三 | 信息学院 |
学院表(主键:学院名称):
| 学院名称 | 学院电话 |
|---|---|
| 信息学院 | 010-12345678 |
4. 第四范式(4NF)
Section titled “4. 第四范式(4NF)”含义:在满足3NF的基础上,消除多值依赖(存在多个属性间接依赖同一张表)。
目标:解决“多对多关系直接存储”导致的冗余问题。
示例:
×:学生课程表中直接存储学生ID和课程ID的多对多关系:
| 学生ID | 课程ID | 课程名称 | 教师 |
|---|---|---|---|
| 1001 | C001 | 数学 | A老师 |
| 1001 | C002 | 英语 | B老师 |
| 1002 | C001 | 数学 | A老师 |
| 1002 | C002 | 英语 | B老师 |
PS:学生课程表中存在多值依赖,即学生ID和课程ID直接存储在同一张表中。
√:拆分为两张表:
学生课程表(主键:学生ID和课程ID):
| 学生ID | 课程ID |
|---|---|
| 1001 | C002 |
| 1002 | C001 |
| 1002 | C002 |
| 1001 | C001 |
课程表(主键:课程ID):
| 课程ID | 课程名称 | 教师 |
|---|---|---|
| C001 | 数学 | A老师 |
| C002 | 英语 | B老师 |
三、BC范式(巴斯-科德范式)
Section titled “三、BC范式(巴斯-科德范式)”含义:BCNF是3NF的加强版,要求所有非主属性的依赖关系中,决定因素必须是超级码(即决定因素包含主键)
目标:解决3NF未覆盖的“主属性依赖主属性”问题。
示例:
×:反例:项目表(主键:项目ID)中存储负责人和部门:
| 项目ID | 负责人 | 部门 |
|---|---|---|
| P001 | 张三 | 技术部 |
| P003 | 王五 | 财务部 |
PS:项目表中存在主属性依赖主属性,即项目ID决定了负责人和部门,因此不满足BCNF。
√:满足BCNF:
项目表(主键:项目ID):
| 项目ID | 负责人 |
|---|---|
| P001 | 张三 |
| P003 | 王五 |
项目负责人表(主键:负责人):
| 负责人 | 部门 |
|---|---|
| 张三 | 技术部 |
| 王五 | 财务部 |
四、如何划分范式
Section titled “四、如何划分范式”1. 第一步:满足1NF
确保每个字段不可再分(原子性)。
2.第二步:满足2NF
检查是否存在“部分依赖”(非主属性依赖主键的一部分),若有则拆分表。
3.第三步:满足3NF
检查是否存在“传递依赖”(非主属性依赖其他非主属性),若有则拆分表。
4.第四步:满足BCNF
检查是否存在“主属性依赖主属性且不满足超级码”,若有则拆分表。
5.第五步:满足4NF
检查是否存在“多对多关系导致的冗余”,若有则通过中间表拆分。
五、实例总结
Section titled “五、实例总结”| 范式级别 | 核心问题 | 解决方案 | 示例场景 |
|---|---|---|---|
| 1NF | 字段可再分 | 拆分字段为原子性 | 存储多值字段(如数组) |
| 2NF | 部分依赖 | 将依赖部分拆分到新表 | 联合主键表(如订单表) |
| 3NF | 传递依赖 | 将被依赖字段拆分到新表 | 学生表存储学院信息 |
| BC范式 | 主属性非超级码决定 | 拆分为独立表 | 项目表存储部门负责人 |
| 4NF | 多值依赖 | 通过中间表分解多对多关系 | 学生选课关系 |
六、记忆口诀
Section titled “六、记忆口诀”1NF:字段不可分,原子性第一。
2NF:主键要完整,部分依赖拆。
3NF:非主不传传,依赖要直接。
BCNF:决定因素是超码,主属性不乱依赖。
4NF:多对多拆中间,避免冗余存。