闭卷专题二:规范化理论
规范化理论对应教材第6章“关系数据理论”,也是闭卷考核内容。它研究的问题可以概括为:
一个关系表怎样设计,才能减少数据冗余、避免修改异常,并且保持原有业务约束?这部分常见题型包括:
根据函数依赖求候选码;判断关系模式属于第几范式;指出插入、删除、更新异常;把关系模式分解到3NF或BCNF;判断分解是否无损连接、是否保持函数依赖。1. 为什么需要规范化
Section titled “1. 为什么需要规范化”假设将学生、课程和选课成绩全部放在一张表中:
Enroll(Sno, Sname, Dept, Cno, Cname, Teacher, Grade)一位学生选多门课程时,姓名和院系会重复保存;一门课程被多名学生选择时,课程名和教师也会重复保存。
样例:
| Sno | Sname | Dept | Cno | Cname | Teacher | Grade |
|---|---|---|---|---|---|---|
| S01 | 张明 | 计算机 | C01 | 数据库 | 王老师 | 88 |
| S01 | 张明 | 计算机 | C02 | 操作系统 | 李老师 | 92 |
| S02 | 李欣 | 软件 | C01 | 数据库 | 王老师 | 85 |
这种设计可能出现以下问题。
1.1 数据冗余
Section titled “1.1 数据冗余”学生姓名、院系随着每次选课反复保存;课程名称、教师随着每个学生选课反复保存。1.2 更新异常
Section titled “1.2 更新异常”如果课程 C01 的教师更换,需要修改多行。漏改任何一行,就会出现同一课程对应两个教师的矛盾数据。
1.3 插入异常
Section titled “1.3 插入异常”如果新开设一门课程但还没有学生选课,在这张大表中可能无法单独保存课程信息,因为主键中需要学生信息。
1.4 删除异常
Section titled “1.4 删除异常”如果删除最后一个选修 C01 的学生记录,课程 C01 的名称和教师信息也会随之丢失。
规范化的目标,就是通过合理分解关系模式来减少这些异常。
2. 函数依赖
Section titled “2. 函数依赖”2.1 定义
Section titled “2.1 定义”在关系模式 R 中,如果属性组 X 的值确定后,属性组 Y 的值也被唯一确定,就称:
Y 函数依赖于 X记作:
X → Y例如:
Sno → Sname, DeptCno → Cname, Teacher(Sno, Cno) → Grade含义分别是:
学号能够确定学生姓名和院系;课程号能够确定课程名称和教师;一个学生对一门课程的选课组合能够确定成绩。2.2 函数依赖来自语义
Section titled “2.2 函数依赖来自语义”函数依赖不能只看当前数据碰巧没有重复,而要根据业务规则判断。
例如当前表中没有重名学生,也不能因此写:
Sname → Sno因为现实规则并没有保证不同学生绝不重名。
3. 码、主属性与非主属性
Section titled “3. 码、主属性与非主属性”3.1 候选码
Section titled “3.1 候选码”候选码是能够唯一确定关系中全部属性,并且本身不可再删减的属性组。
对于:
Enroll(Sno, Sname, Dept, Cno, Cname, Teacher, Grade)若函数依赖为:
Sno → Sname, DeptCno → Cname, Teacher(Sno, Cno) → Grade则:
(Sno, Cno) → 所有属性而单独 Sno 或单独 Cno 都不能确定成绩和全部信息。因此候选码为:
(Sno, Cno)3.2 主码
Section titled “3.2 主码”从候选码中选一个作为主要标识,称为主码。若只有一个候选码,通常它就是主码。
3.3 主属性与非主属性
Section titled “3.3 主属性与非主属性”主属性:出现在任一候选码中的属性。非主属性:不出现在任何候选码中的属性。在上例中:
主属性:Sno、Cno非主属性:Sname、Dept、Cname、Teacher、Grade4. 完全依赖、部分依赖与传递依赖
Section titled “4. 完全依赖、部分依赖与传递依赖”4.1 完全函数依赖
Section titled “4.1 完全函数依赖”如果 Y 依赖于组合属性 X,而删除 X 中任何一个属性后都不能确定 Y,则称 Y 完全函数依赖于 X。
例如:
(Sno, Cno) → Grade单靠学生号不能确定某门课程成绩,单靠课程号也不能确定某个学生成绩。因此成绩完全依赖于联合码。
4.2 部分函数依赖
Section titled “4.2 部分函数依赖”如果 Y 依赖于联合码,但实际上仅依赖联合码的一部分,则称为部分依赖。
例如在 Enroll 中:
(Sno, Cno) → Sname但实际上:
Sno → Sname因此 Sname 对候选码 (Sno, Cno) 是部分依赖。同理:
Dept 部分依赖于 Sno;Cname、Teacher 部分依赖于 Cno。4.3 传递函数依赖
Section titled “4.3 传递函数依赖”如果:
X → YY → Z且Y不是候选码,Z不直接依赖于X的码含义则可以说 Z 传递依赖于 X。
例如关系:
Student(Sno, DeptNo, DeptName)函数依赖:
Sno → DeptNoDeptNo → DeptName则:
Sno → DeptName属于传递依赖。
5. 第一范式 1NF
Section titled “5. 第一范式 1NF”5.1 定义
Section titled “5.1 定义”一个关系模式中的每个属性值都必须是不可再分的原子值,才满足第一范式。
不符合1NF的例子:
| StudentID | StudentName | Phones |
|---|---|---|
| S01 | 张明 | 138xxxx, 139xxxx |
Phones 一列中保存多个电话号码,不便于查询和约束。
改进方法:
Student(StudentID, StudentName)StudentPhone(StudentID, Phone)5.2 记忆要点
Section titled “5.2 记忆要点”1NF解决的是属性值不可再分的问题。关系数据库中的规范表通常首先必须满足1NF。6. 第二范式 2NF
Section titled “6. 第二范式 2NF”6.1 定义
Section titled “6.1 定义”关系模式满足1NF,并且每一个非主属性都完全函数依赖于任一候选码,则满足2NF。
6.2 什么时候容易违反2NF
Section titled “6.2 什么时候容易违反2NF”当候选码是联合码时,尤其要检查非主属性是否只依赖其中一部分。
对于:
Enroll(Sno, Sname, Dept, Cno, Cname, Teacher, Grade)候选码:(Sno, Cno)存在:
Sno → Sname, DeptCno → Cname, Teacher(Sno, Cno) → Grade这里多个非主属性部分依赖于联合码,所以该关系不满足2NF。
6.3 分解到2NF
Section titled “6.3 分解到2NF”将只依赖学号、只依赖课程号、依赖完整选课组合的信息拆开:
Student(Sno, Sname, Dept)Course(Cno, Cname, Teacher)SC(Sno, Cno, Grade)这样:
Student中的非主属性完全依赖于Sno;Course中的非主属性完全依赖于Cno;SC中的Grade完全依赖于(Sno, Cno)。7. 第三范式 3NF
Section titled “7. 第三范式 3NF”7.1 定义的直观理解
Section titled “7.1 定义的直观理解”满足2NF后,如果不存在非主属性对候选码的传递依赖,则通常可认为满足3NF。
更规范地说,对于每一个非平凡函数依赖 X → Y,应至少满足:
X是超码;或Y是主属性。7.2 违反3NF的例子
Section titled “7.2 违反3NF的例子”Student(Sno, Sname, DeptNo, DeptName)函数依赖:
Sno → Sname, DeptNoDeptNo → DeptName候选码为 Sno,不存在部分依赖,因此它可以满足2NF。但是:
Sno → DeptNo → DeptNameDeptName 传递依赖于主码,所以不满足3NF。
7.3 分解到3NF
Section titled “7.3 分解到3NF”Student(Sno, Sname, DeptNo)Department(DeptNo, DeptName)这样院系名称只存放在院系表中,修改院系名称时不会产生多行不一致。
8. BCNF
Section titled “8. BCNF”8.1 定义
Section titled “8.1 定义”如果关系模式中的每一个非平凡函数依赖 X → Y 的决定因素 X 都是超码,则该关系满足 BCNF。
直观记忆:
BCNF要求更严格:凡是能够决定其他属性的属性组,都必须足够强,能够唯一确定整行。8.2 3NF与BCNF的关系
Section titled “8.2 3NF与BCNF的关系”满足BCNF一定满足3NF;满足3NF不一定满足BCNF。8.3 典型理解例
Section titled “8.3 典型理解例”假设:
Teaching(Student, Course, Teacher)业务规则:
一个学生选一门课对应一位教师:(Student, Course) → Teacher一位教师只负责一门课程:Teacher → Course候选码可能包括:
(Student, Course)(Student, Teacher)依赖 Teacher → Course 中,Teacher 并不是超码,因此该模式不满足BCNF。它可分解为:
TeacherCourse(Teacher, Course)StudentTeacher(Student, Teacher)9. 多值依赖与第四范式的了解内容
Section titled “9. 多值依赖与第四范式的了解内容”教材的规范化章节还涉及多值依赖。例如一个课程可能独立对应多个教师和多本参考书:
CourseTeacherBook(Course, Teacher, Book)如果教师集合与参考书集合互不依赖,就会组合产生大量重复元组。可表示为:
Course →→ TeacherCourse →→ Book可分解为:
CourseTeacher(Course, Teacher)CourseBook(Course, Book)闭卷范围通常更核心的是函数依赖与1NF、2NF、3NF、BCNF,但如果题目出现“多值依赖”或“第四范式”,应知道它关注的是彼此独立的多值事实引起的冗余。
10. 模式分解的两个重要性质
Section titled “10. 模式分解的两个重要性质”10.1 无损连接分解
Section titled “10.1 无损连接分解”分解后,将子关系自然连接起来,应能恢复原关系中的真实信息,并且不能产生额外的错误元组。
例如:
Student(Sno, Sname, Dept)SC(Sno, Cno, Grade)它们通过 Sno 连接,可以恢复学生与其成绩信息。若分解时丢失了用于连接的关键属性,就可能无法正确恢复。
对于分解 R → R1, R2,常用判断思路是:
若交集属性 R1 ∩ R2 能函数决定 R1 或 R2 中的全部属性,则该二元分解通常为无损连接。10.2 保持函数依赖
Section titled “10.2 保持函数依赖”分解后,原来的重要函数依赖应尽可能在各个子关系内部直接检查,而不需要先把多张表连接起来才能验证。
例如分解后:
Student(Sno, Sname, Dept)Course(Cno, Cname, Teacher)SC(Sno, Cno, Grade)原有依赖:
Sno → Sname, DeptCno → Cname, Teacher(Sno, Cno) → Grade均可以在某一张子表中直接检查,因此依赖得到保持。
11. 规范化完整解题流程
Section titled “11. 规范化完整解题流程”拿到关系模式和函数依赖集后,可以按下面流程答题。
第一步:写出函数依赖
Section titled “第一步:写出函数依赖”从题意提取:
编号决定什么;联合编号决定什么;某个业务属性是否能决定另一个属性。第二步:求候选码
Section titled “第二步:求候选码”找出能够推出全部属性、并且不能再删去任何一个属性的最小属性组。
第三步:区分主属性与非主属性
Section titled “第三步:区分主属性与非主属性”出现在候选码中的属性为主属性,其余为非主属性。
第四步:判断范式
Section titled “第四步:判断范式”顺序判断:
属性是否原子化 → 1NF是否存在非主属性对联合码的部分依赖 → 2NF是否存在非主属性对码的传递依赖 → 3NF是否所有决定因素都是超码 → BCNF第五步:指出异常
Section titled “第五步:指出异常”结合业务说明:
数据重复在哪里;新增某类信息为何无法插入;修改某信息为何需改多行;删除某记录为何会误删其他信息。第六步:进行分解
Section titled “第六步:进行分解”把每一类“由决定因素确定的事实”放到独立关系中,同时保留业务联系表。
第七步:说明分解效果
Section titled “第七步:说明分解效果”至少说明:
消除了哪些部分依赖或传递依赖;分解后各表主键是什么;重要依赖是否仍能检查;连接是否能够还原原有业务信息。12. 综合例题
Section titled “12. 综合例题”给定关系:
Borrow(Sno, Sname, BookNo, BookName, Publisher, BorrowDate, ReturnDate)业务规则:
Sno → SnameBookNo → BookName, Publisher(Sno, BookNo, BorrowDate) → ReturnDate12.1 求候选码
Section titled “12.1 求候选码”一次借阅由学生、图书和借阅日期共同确定,因此候选码为:
(Sno, BookNo, BorrowDate)12.2 判断问题
Section titled “12.2 判断问题”Sname只依赖Sno,是对联合码的部分依赖;BookName和Publisher只依赖BookNo,也是部分依赖;因此原关系不满足2NF。12.3 分解
Section titled “12.3 分解”Student(Sno, Sname)Book(BookNo, BookName, Publisher)BorrowRecord(Sno, BookNo, BorrowDate, ReturnDate)12.4 说明效果
Section titled “12.4 说明效果”学生姓名只在Student中保存一次;图书基本信息只在Book中保存一次;BorrowRecord仅记录一次借阅事实;消除了由于重复保存学生和图书信息造成的更新、插入和删除异常。13. 易混点总结
Section titled “13. 易混点总结”| 易混内容 | 正确理解 |
|---|---|
| 主键与候选码 | 候选码可以有多个,主键是被选择的一个候选码 |
| 部分依赖 | 只在联合候选码场景下重点出现,非主属性只依赖码的一部分 |
| 传递依赖 | 非主属性通过另一个非主属性间接依赖于码 |
| 2NF与3NF | 2NF消除部分依赖,3NF进一步消除非主属性的传递依赖 |
| 3NF与BCNF | BCNF更严格,所有决定因素都必须是超码 |
| 分解不是随便拆表 | 还要考虑无损连接与函数依赖保持 |
14. 闭卷背诵版
Section titled “14. 闭卷背诵版”规范化是利用函数依赖等理论改进关系模式的过程,目的在于减少数据冗余,避免插入异常、删除异常和更新异常。
函数依赖X→Y表示属性组X的值能够唯一确定属性组Y的值。候选码是能够唯一确定全部属性且不可再约简的属性组;出现在候选码中的属性称为主属性。
1NF要求属性值不可再分;2NF要求在满足1NF的基础上,非主属性完全依赖于候选码,消除部分依赖;3NF进一步消除非主属性对候选码的传递依赖;BCNF要求每一个非平凡函数依赖的决定因素都是超码。
关系模式分解时既要提高范式,也应考虑无损连接和保持函数依赖,使分解后的表能够正确还原业务数据,并方便检查原有约束。