数据库范式(Normalization)是一套设计关系数据库的规则,旨在减少数据冗余、避免更新异常(如插入、删除和修改异常),并确保数据一致性。范式从低到高分为多个级别,每个级别基于前一级别并添加更严格的约束。下面我将逐步详解主要范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)和 Boyce-Codd 范式(BCNF),使用中文解释,并辅以示例和数学表达式说明函数依赖关系。
1. 第一范式(1NF)
- 定义:关系表中的每个属性(列)必须是原子的,即不可再分。所有字段的值都是单一值,不能包含集合、数组或重复组。
- 目的:消除重复数据,确保基本结构规范。
- 数学表示:设关系 RRR 有属性集 A1,A2,…,AnA_1, A_2, \ldots, A_nA1,A2,…,An,则对任意元组,每个 AiA_iAi 的值是标量(如整数、字符串),不允许多值或嵌套结构。
- 示例:
- 非1NF表(学生选课表):
学生ID 课程列表 101 数学, 物理 102 化学 - 问题:课程列表不是原子值(包含多个课程)。
- 转换为1NF后:
学生ID 课程 101 数学 101 物理 102 化学 - 改进:每个单元格只存储单一值。
- 非1NF表(学生选课表):
2. 第二范式(2NF)
- 定义:在满足1NF的基础上,消除非主属性对主键的部分依赖。即所有非主属性必须完全依赖于整个主键(不能只依赖于主键的一部分)。
- 目的:减少冗余,避免更新异常。
- 数学表示:设关系 RRR 的主键为 KKK(可能为复合键),非主属性集为 NNN。如果存在部分依赖(如 K′⊂KK' \subset KK′⊂K 且 K′→NK' \to NK′→N),则需分解表。函数依赖需满足:对所有非主属性 Ai∈NA_i \in NAi∈N,有 K→AiK \to A_iK→Ai(完全依赖)。
- 示例:
- 非2NF表(学生选课成绩表),假设主键为(学生ID, 课程ID):
学生ID 课程ID 学生姓名 成绩 101 MATH01 张三 90 101 PHYS02 张三 85 - 问题:学生姓名只依赖于学生ID(主键的一部分),而非整个主键(学生ID + 课程ID)。这导致冗余(如张三姓名重复)和异常(如删除某课程会丢失学生姓名)。
- 转换为2NF:分解为两个表。
- 表1(学生信息):主键为学生ID
学生ID 学生姓名 101 张三 - 表2(选课成绩):主键为(学生ID, 课程ID)
学生ID 课程ID 成绩 101 MATH01 90 101 PHYS02 85 - 改进:非主属性(学生姓名)完全依赖于主键。
- 表1(学生信息):主键为学生ID
- 非2NF表(学生选课成绩表),假设主键为(学生ID, 课程ID):
3. 第三范式(3NF)
- 定义:在满足2NF的基础上,消除非主属性对主键的传递依赖。即非主属性不能依赖于其他非主属性(只能直接依赖于主键)。
- 目的:进一步减少冗余,确保数据修改一致性。
- 数学表示:设关系 RRR 的属性集为 UUU,主键为 KKK,非主属性集为 NNN。如果存在传递依赖(如 K→AK \to AK→A 且 A→BA \to BA→B,其中 A,B∈NA, B \in NA,B∈N),则需分解。函数依赖需满足:对所有 Ai∈NA_i \in NAi∈N,不存在 X→AiX \to A_iX→Ai 且 X↛KX \not\to KX→K(XXX 是属性子集)。
- 示例:
- 非3NF表(学生宿舍表),假设主键为学生ID:
学生ID 宿舍楼 宿舍费用 101 A栋 1000 102 B栋 1200 - 问题:宿舍费用依赖于宿舍楼(非主属性),而非直接依赖于主键(学生ID)。这导致冗余(如A栋费用重复)和异常(如修改A栋费用需更新多行)。
- 转换为3NF:分解为两个表。
- 表1(学生宿舍):主键为学生ID
学生ID 宿舍楼 101 A栋 102 B栋 - 表2(宿舍费用):主键为宿舍楼
宿舍楼 宿舍费用 A栋 1000 B栋 1200 - 改进:非主属性(宿舍费用)直接依赖于主键。
- 表1(学生宿舍):主键为学生ID
- 非3NF表(学生宿舍表),假设主键为学生ID:
4. Boyce-Codd 范式(BCNF)
- 定义:在满足3NF的基础上,进一步消除主属性对非主键的依赖。即所有函数依赖的决定因素(左侧)必须是候选键(超键)。
- 目的:处理3NF无法覆盖的异常情况,确保更严格的依赖关系。
- 数学表示:设关系 RRR 的函数依赖集为 FFF,则对所有 X→Y∈FX \to Y \in FX→Y∈F,XXX 必须是超键(即 XXX 能唯一决定 RRR 的所有属性)。如果存在 X→YX \to YX→Y 且 XXX 不是超键,则需分解。
- 示例:
- 非BCNF表(课程教师表),假设属性为(课程ID, 教师ID, 教师职称),函数依赖为:课程ID → 教师ID,教师ID → 教师职称。
课程ID 教师ID 教师职称 MATH01 T001 教授 PHYS02 T002 副教授 - 问题:教师职称依赖于教师ID(非候选键),但课程ID → 教师ID 表示教师ID 不是超键(候选键可能是课程ID或教师ID)。这导致异常(如一个教师教多门课时,职称冗余)。
- 转换为BCNF:分解为两个表。
- 表1(课程教师):主键为课程ID
课程ID 教师ID MATH01 T001 PHYS02 T002 - 表2(教师信息):主键为教师ID
教师ID 教师职称 T001 教授 T002 副教授 - 改进:所有依赖的决定因素(如教师ID)都是候选键。
- 表1(课程教师):主键为课程ID
- 非BCNF表(课程教师表),假设属性为(课程ID, 教师ID, 教师职称),函数依赖为:课程ID → 教师ID,教师ID → 教师职称。
更高范式(简要说明)
- 第四范式(4NF):处理多值依赖,确保没有非平凡多值依赖。
- 第五范式(5NF):处理连接依赖,确保表可无损分解。
- 实际应用中,3NF 或 BCNF 通常足够;更高范式可能增加复杂性,需权衡性能。
总结
- 范式级别关系:1NF ⊂\subset⊂ 2NF ⊂\subset⊂ 3NF ⊂\subset⊂ BCNF ⊂\subset⊂ 4NF ⊂\subset⊂ 5NF(符号 $ \subset $ 表示包含关系)。
- 优点:减少冗余、提高数据完整性、避免异常。
- 缺点:高级范式可能导致表过多,影响查询性能;设计时需结合实际需求(如反规范化)。
- 在实际数据库设计中,建议从1NF开始逐步优化,使用函数依赖分析工具辅助。例如,通过函数依赖图验证范式级别。