# 数据库范式
# 什么是数据库范式
数据库范式(Normalization)是一种设计关系型数据库的方法,它旨在减少数据冗余,提高数据的一致性和可靠性,避免数据修改时出现异常。数据库范式通常分为一到五个级别,每个级别对应一组设计规则。
范式越高,数据冗余越少,数据一致性和可靠性越高。但是,范式过高也可能会带来一些问题,如增加了数据库的复杂性和查询的开销,需要根据实际应用场景来确定使用哪个范式。
# 层级分类
# 1NF(第一范式)
关系模式中的所有属性都是原子性的,即不可再分。
# 2NF(第二范式)
关系模式必须满足第一范式,且不存在非关键字属性对主键的部分依赖。
# 3NF(第三范式)
关系模式必须满足第二范式,且不存在非关键字属性对其他非关键字属性的传递依赖。
# BCNF(Boyce-Codd 范式)
关系模式必须满足第一范式,且不存在非主属性对主属性的非平凡依赖关系。
# 4NF(第四范式)
关系模式必须满足第三范式,且不存在多值依赖。
# 5NF(第五范式)
关系模式必须满足第四范式,且不存在连接依赖。
# 小题目
让我们通过一些题目来感受一下吧!!
# Ex1
设有关系 R(工号,姓名,工种,定额),则 R 是属于第 2 范式,将其转化为第三范式
根据关系 R(工号,姓名,工种,定额),我们可以看出工号和姓名是候选键,因为它们可以唯一地标识每个元组。同时,我们也可以看出工种和定额这两个属性完全依赖于候选键,因此关系 R 符合 2NF 的要求。
现在我们来考虑将 R 转化为 3NF 的过程。根据 3NF 的要求,我们需要消除任何非主属性对主键的传递依赖。因此,我们需要检查每个非主属性是否直接依赖于主键,或者是直接依赖于其他非主属性。
在关系 R 中,我们可以发现定额属性直接依赖于工种属性,而工种属性并不是主键的一部分。因此,我们可以将定额和工种拆分到一个新的关系中,以消除定额对于工种的传递依赖,从而使得关系 R 满足 3NF 的要求。
拆分后的两个关系如下:
- R1(工号,姓名,工种):该关系包含了工号、姓名和工种三个属性,其中工号和姓名作为候选键,工种是一个非主属性,但它直接依赖于主键。因此,关系 R1 符合 2NF 和 3NF 的要求。
- R2(工种,定额):该关系包含了工种和定额两个属性,其中工种作为主键,定额是一个非主属性,但它直接依赖于主键。因此,关系 R2 符合 2NF 和 3NF 的要求。
最终,我们将关系 R 转化为两个符合 3NF 的关系 R1 和 R2,符合 3NF 的要求。
# Ex2
设有关系 STUDENT (S#,SNAME,SDEPT,MNAME,CNAME,GRADE),S#,CNAME 为候选码,设关系中有如下函数依赖:
S#,CNAME→SNAME,SDEPT,MNAME
S#→SNAME,SDEPT,MNAME
S#,CNAME→GRADE
SDEPT→MNAME
试求下列问题:
(1)关系 STUDENT 属于第几范式?
(2)如果关系 STUDENT 不属于 BCNF,请将关系 STUDENT 逐步分解为 BCNF。
要求:写出达到每一级范式的分解过程,并指明消除什么类型的函数依赖。
(1)1NF
(2)首先消除非主属性对候选码的部分依赖,即消除部分函数依赖
(S#,CNAME)->(SNAME,SDEPT,MNAME)
R 分解为:
R1(S#,SNAME,SDEPT,MNAME)
R2(S#,CNAME,GRADE)
R 至此分解为 2NF
此时 R1 中存在非主属性对候选码的传递依赖,即消除传递依赖
(S#)->(SDEPT)
(SDEPT)->(MNAME)
R1 分解为:
R11(S#,SNAME,SDEPT)
R12(SDEPT,MNAME)
R1 至此分解为 3NF
此时 R11,R12,R2 可以得出的函数依赖:
(S#,CNAME)->(GRADE)
(S#)->(SNAME),(S#)->(SDEPT)
(SDEPT)->(MNAME)
由此可以看出,数据表中的每个非主属性都完全依赖于候选键,即每个非主属性都不只依赖于候选键的一部分,且非主属性无法决定另一个非主属性,即不存在非平凡函数依赖。
上述关系表 R11,R12,R2 满足 BCNF
# Ex3
一个关系模式不属于第二范式可能会产生 ()、() 和 ( ) 等几个问题,解决的办法是 ( )。
-
第一空:
插入异常
-
第二空:
删除异常
-
第三空:
修改异常
-
第四空:
投影分解
# 关键词
# 候选码和非主属性
候选码和非主属性是关系数据库中的两个概念,它们之间有一定的关系。
候选码(Candidate Key)指的是能够唯一标识关系模式中每一条记录的属性集合。一个关系模式可能有多个候选码,但是其中只有一个会被选择作为主键(Primary Key)来标识每一条记录。通常情况下,主键会被用来建立关系模式之间的联系,因此选择一个恰当的候选码作为主键是关系数据库设计中的重要步骤。
非主属性指的是关系模式中除了主键之外的属性。一个关系模式可能包含多个非主属性,它们之间可以存在依赖关系。例如,一个关系模式 R(A,B,C)中,如果存在函数依赖 A→B,则 B 是非主属性。
候选码和非主属性之间的关系在于,一个候选码包含了所有的主属性,而非主属性可能依赖于主属性,也可能存在依赖于其他非主属性的情况。在进行关系数据库设计时,我们需要通过确定候选码和依赖关系来规范化关系模式,从而消除数据冗余和不一致性的问题。通常情况下,我们会选择最小的候选码作为主键,并确保所有非主属性都完全依赖于主键,以保证数据的完整性和一致性。
# 平凡依赖关系
平凡依赖关系是指对于一个属性集合 X,在一个关系 R 中如果 X 的任意超集都可以唯一地确定 X,那么 X 对于 R 就是平凡的依赖。例如,在一个关系 R(A, B, C),如果存在函数依赖 A→A,那么 A 对于 R 来说是一个平凡依赖。因为 A 的任意超集都可以唯一地确定 A 本身,即 A 已经包含了它所依赖的属性。
可以这样理解,一个属性集合如果能够唯一地确定自己,那么它就是平凡的依赖。例如,在一个关系 R(A, B, C),如果存在函数依赖 A→A,那么 A 对于 R 来说是一个平凡依赖,因为属性集合 A 已经包含了它所依赖的属性 A 本身,即 A 已经能够唯一地确定自己。而非平凡的依赖是指一个属性集合不能唯一地确定自己,需要依赖于其他属性才能确定自己,例如在关系 R(A, B, C)中,存在函数依赖 A→B,B 就是一个非平凡依赖,因为 B 不能唯一地确定自己,需要依赖于 A 才能确定。
# 传递依赖
传递依赖(Transitive Dependency)指的是一个非主属性依赖于另一个非主属性的非主属性。例如,一个关系模式 R(A,B,C)中,如果存在函数依赖 A→B 和 B→C,则 C 对 A 存在传递依赖。这种情况下,如果我们要更新 A 的值,就会导致 C 的值也随之改变,从而引起数据不一致的问题。