文章目录
第一范式(1NF)
第一范式是关系型数据库的最基本要求,任何关系型数据库的表都必须满足1NF。
判断标准
- 原子性:表中的每一列都必须是不可再分的原子值。这意味着一个字段不能包含多个值或重复的组。
样例参考
假设有一个学生选课表,设计如下:
| 学号 | 姓名 | 选修课程 |
|---|---|---|
| 1001 | 张三 | 数学, 英语 |
| 1002 | 李四 | 物理 |
问题:"选修课程"这一列包含了多个值(数学和英语),违反了原子性原则。
修正方案:将"选修课程"列拆分,确保每行只有一个课程。
| 学号 | 姓名 | 选修课程 |
|---|---|---|
| 1001 | 张三 | 数学 |
| 1001 | 张三 | 英语 |
| 1002 | 李四 | 物理 |
现在,每个字段都只包含一个不可分割的值,该表满足第一范式。
第二范式(2NF)
第二范式建立在第一范式的基础上,主要解决数据冗余问题,特别是当表有联合主键时。
判断标准
- 前提:必须满足第一范式。
- 核心规则:表中的所有非主键字段必须"完全依赖"于整个主键,而不能只依赖于主键的一部分(即消除"部分依赖")。
样例参考
假设有一个订单详情表,主键是(订单ID, 产品ID)。
| 订单ID | 产品ID | 产品名称 | 购买数量 | 订单日期 |
|---|---|---|---|---|
| 1001 | P01 | 笔记本 | 2 | 2023-01-01 |
| 1001 | P02 | 钢笔 | 5 | 2023-01-01 |
分析:
- 主键是(订单ID, 产品ID)的组合。
- "购买数量"依赖于(订单ID, 产品ID),即某个订单里的某个产品买了多少。这是完全依赖。
- "产品名称"只依赖于"产品ID",与"订单ID"无关。这就是部分依赖。
- "订单日期"只依赖于"订单ID",与"产品ID"无关。这也是部分依赖。
问题:产品名称和订单日期会大量重复,造成冗余。
修正方案:将表拆分成三个表,消除部分依赖。
- 订单表:(订单ID, 订单日期)
- 产品表:(产品ID, 产品名称)
- 订单详情表:(订单ID, 产品ID, 购买数量)
现在,每个非主键字段都完全依赖于其所在表的主键,该设计满足第二范式。
第三范式(3NF)
第三范式建立在第二范式的基础上,进一步消除数据冗余。
判断标准
- 前提:必须满足第二范式。
- 核心规则:表中的所有非主键字段必须"直接依赖"于主键,而不能存在传递依赖。即,非主键字段之间不能有依赖关系。
样例参考
假设有一个员工信息表,主键是员工ID。
| 员工ID | 姓名 | 部门名称 | 部门经理 |
|---|---|---|---|
| E01 | 张三 | 研发部 | 王经理 |
| E02 | 李四 | 市场部 | 赵经理 |
| E03 | 王五 | 研发部 | 王经理 |
分析:
- 主键是"员工ID"。
- "姓名"直接依赖于"员工ID"。
- "部门名称"也直接依赖于"员工ID"。
- 但是,"部门经理"并不直接依赖于"员工ID",而是依赖于"部门名称"。因为"研发部"的经理总是"王经理"。
- 这就形成了传递依赖:员工ID -> 部门名称 -> 部门经理。
问题:如果一个部门的经理更换,需要更新所有该部门员工的信息,非常麻烦且容易出错。
修正方案:将存在传递依赖的字段拆分到新表中。
- 员工表:(员工ID, 姓名, 部门名称)
- 部门表:(部门名称, 部门经理)
现在,每个非主键字段都直接依赖于其所在表的主键,消除了传递依赖,该设计满足第三范式。
巴斯-科德范式(BCNF)
BCNF是第三范式的一个增强版本,被认为是"修正的第三范式"。它处理了3NF中未涵盖的一些特殊情况。
判断标准
- 前提:必须满足第三范式。
- 核心规则:对于表中的每一个非平凡函数依赖 X -> Y,X 必须是一个超键(即X必须包含候选键)。简单来说,就是所有决定其他字段的字段(决定因素)本身必须是主键或候选键。
样例参考
假设一个仓库管理库存的规则是:一个仓库由一名管理员负责,但一个管理员可以管理多个仓库;一个仓库可以存放多种物品,一种物品也可以存放在多个仓库。
| 仓库ID | 物品ID | 管理员 |
|---|---|---|
| WH1 | I001 | 张三 |
| WH1 | I002 | 张三 |
| WH2 | I001 | 李四 |
分析:
- 候选键是(仓库ID, 物品ID),因为它们的组合能唯一标识一行。
- 但是,存在一个依赖关系:仓库ID -> 管理员。一个仓库只对应一个管理员。
- 这里,"仓库ID"是决定因素,但它本身不是候选键(候选键是组合键)。这违反了BCNF。
问题:如果管理员更换,需要更新该仓库的所有物品记录,造成更新异常。
修正方案:将决定因素不是候选键的依赖关系拆分出去。
- 仓库管理员表:(仓库ID, 管理员)
- 库存表:(仓库ID, 物品ID)
现在,每个表中的所有决定因素都是其候选键,该设计满足BCNF。
第四范式(4NF)
第四范式处理的是比函数依赖更复杂的多值依赖问题。
判断标准
- 前提:必须满足BCNF。
- 核心规则:表中不能存在非平凡的多值依赖。即,一个实体的多个独立的多值属性不应放在同一张表中。
样例参考
假设一个医生可以在多家医院工作,并且拥有多种专业技能。
| 医生 | 医院 | 技能 |
|---|---|---|
| 张医生 | 市一医院 | 外科 |
| 张医生 | 市一医院 | 骨科 |
| 张医生 | 中心医院 | 外科 |
| 张医生 | 中心医院 | 骨科 |
分析:
- "医院"和"技能"都是"医生"的多值属性。
- 但"医院"和"技能"是相互独立的。张医生去哪家医院工作,和他会什么技能没有关系。
- 将它们放在一个表中,会产生大量冗余数据(如示例所示),并且无法独立管理医生和医院、医生和技能的关系。
问题:数据冗余严重,且插入、删除操作会变得复杂。
修正方案:将两个独立的多值依赖拆分成两个表。
- 医生医院表:(医生, 医院)
- 医生技能表:(医生, 技能)
现在,每个表只包含一个多值依赖,消除了多值依赖带来的问题,该设计满足第四范式。
总结
在实际的数据库设计中,通常以达到第三范式(3NF)或BCNF为目标,这能在数据规范性和查询性能之间取得很好的平衡。
- 1NF:基础要求,确保字段原子性。
- 2NF:解决组合主键导致的冗余。
- 3NF:解决非主键字段间的依赖导致的冗余,是主流设计目标。
- BCNF:处理3NF未覆盖的特殊依赖情况,理论更严谨。
- 4NF:处理独立多值属性的问题,适用于特定场景。
需要注意的是,过度规范化可能会导致查询时需要频繁连接(JOIN)多个表,影响读取性能。因此,在一些读密集型应用(如数据仓库、报表系统)中,有时会进行"反规范化",适当增加冗余以提升查询效率。