关系模式基本概念
要建立一套规范化理论,需要研究系统下各组成部分之间的关系,数据库表中主要是属性间的关系。关系模式中的属性之间相互依赖、相互制约的联系称为数据依赖。举一个简单的例子,关系模式 SCD(Student, Course, Department),数据库表如下:
sno | sn | age | dept | mn | cno | score |
---|---|---|---|---|---|---|
S1 | 张三 | 21 | 计算机 | 老王 | C1 | 80 |
S1 | 张三 | 21 | 计算机 | 老王 | C2 | 90 |
S2 | 李四 | 20 | 数学 | 老刘 | C2 | 90 |
sno, cno 可以唯一决定一行数据,所以 sno, cno 是候选码,这张表直接使用会遇到一系列问题:
- 数据冗余:存在大量元素被多次存储;
- 插入异常:学生未选课时无法插入数据,因为主码 cno 为空;
- 删除异常:如果一个学生只选了一门课,在退课时会删除该学生的所有信息;
- 更新异常:修改一个学生的年龄信息,需要修改相关的所有行。
一个好的关系模式数据冗余应该尽可能少,同时避免插入、删除、更新异常。接下来我们就对这个表进行处理,尽可能减少冗余,消除异常。如果我们有一套规范化的理论来指导这个过程,那就再好不过了。我们来研究一下属性之间存在哪些关系,哪些是合理的,哪些可能导致问题。我们只研究函数依赖,函数依赖是指关系模式中各属性间相互依赖、相互制约的联系。在关系模式 SCD 中,我们设 U 是属性全集。F 是 U 上的函数依赖集,有:
U = { sno, sn, age, dept, mn, cno, score }
F = { sno->sn, sno->age, sno->dept, (sno, cno)->score, dept->mn }
函数依赖关系可以分为四类:
- 完全函数依赖,如果
X->Y
且 Y 不依赖于 X 的任何一个真子集,称 Y 对 X 完全函数依赖; - 部分函数依赖,如果 Y 依赖于 X 的某个真子集,称 Y 对 X 部分函数依赖;
- 传递函数依赖,如果
X->Y
,Y!->X
且Y->Z
,则称 Z 对 X 传递函数依赖; - 直接函数依赖,
X->Y
,Y->X
且Y->Z
,则 Z 对 X 直接函数依赖。
根据定义,可知 (sno, cno)->score
为完全函数依赖;(sno, cno)->age
为部分函数依赖;mn 传递依赖于 sno。完全函数依赖及直接函数依赖很直接,部分函数依赖以及传递函数依赖中会存在一些多余的关系,如果我们把部分函数依赖以及传递函数依赖消灭,应该能解决不少问题。
分解的无损连接性
我们通过将大表分解为多个小表的方式,消除不合理的依赖关系,但前提是这个分解过程不能丢失信息。函数依赖可以保证关系分解的无损连接性,即关系模式 R 分解后不会丢失原有的信息,r 等于其投影在 X 上的自然连接 r(X, Y, Z) = r[X, Y] ⋈ r[X, Z]
。
对于关系模式 SCD,有 sno->(sn, age, dept, mn)
,则:SCD = SCD[sno, sn, age, dept, mn] ⋈ SCD[sno, cno, score]
,所以分解的过程中,我们可以选取候选码作为被投影的属性。
关系规范化
数据库表分解后满足什么程度的要求,有一套规范化的衡量标准,这就是范式。在关系数据库的规范化过程中,为不同程度的规范化要求设立的不同标准称为范式。低一级范式的关系模式,通过投影运算可以转化为若干个高一级的关系模式的集合,这叫规范化。
第一范式 1NF
如果关系模式中的所有属性都不可再分,就满足第一范式。显然,SCD 属于第一范式,完整的函数依赖如下:
(sno, cno) F-> score
sno->sn, (sno, cno) P->sn
sno->age, (sno, cno) P->age
sno->dept, (sno, cno) P->dept
dept->mn, sno T->mn, (sno, cno) P-> mn
其中既存在完全函数依赖,也存在部分函数依赖和传递函数依赖,正是由于关系中存在着复杂的函数依赖,才导致数据操作中出现了种种弊端。克服这些弊端的方法是用投影运算将关系分解,去掉过于复杂的函数依赖关系,向更高一级的范式进行转换。如果我们把非主属性对主属性的部分函数依赖消除,就可达到第二范式。
第二范式 2NF
若关系模式 R 属于第一范式,且每个非主属性都完全函数依赖于 R 的候选码,则称 R 属于第二范式。SCD 中 sno, cno 为主属性,sn, age, dept, mn, score 都是非主属性。分解时遵循的原则是,让一个关系只描述一个实体或者实体间的联系,如果多于一个实体或联系,就进行投影分解,SCD 至少描述了一个学生实体和一个学生与课程的关系,因此可分解为两个关系:SD(sno, sn, age, dept, mn) 及 SC(sno, cno, score)。
非主属性 sn, age, dept, mn 完全函数依赖于 sno,score 完全函数依赖于 (sno, cno),则 SC, SD 都属于第二范式。但是这种分解方式仍然存在问题:
- 数据冗余:每个系名和系主任的名字存储的次数等于该系的学生人数。
- 插入异常:当一个新系没有招生时,有关该系的信息无法插入。
- 删除异常:某系学生全部毕业而没有招生时,删除全部学生的记录也随之删除了该系的有关信息。
- 更新异常:更换系主任时,仍需改动较多的学生记录。
SD 中存在 mn 存在对 sno 的传递依赖,即 mn 与 sno 存在间接相关性,通过投影分解消除非主属性对主属性的传递函数依赖,就可达到第三范式。
第三范式 3NF
如果关系模式 R 属于第二范式,且每个非主属性都不传递依赖于 R 的候选码,则称 R 属于第三范式。SD 中存在着两个实体,学生和系,进行投影分解:S(sno, sn, age, dept),D(dept, mn),无传递函数依赖。
分解到第三范式,基本已经消除了之前提到的各种异常,数据的冗余性也得到了一定程度的降低。3NF 只限制了非主属性对码的依赖关系,没有限制主属性对码的依赖关系,如果进一步消除主属性之间的依赖关系,可得到更高一级的范式。
BC 范式
若关系模式 R 属于第一范式,且 R 中每个决定因素都包含候选码,成 R 属于 BC 范式。BCNF 完全消除属性间的部分函数依赖及传递函数依赖。可知,全码的关系模式必属于 BCNF。
如果一个关系数据库中所有的关系模式都属于 BCNF,那么在函数依赖的范畴内,已经实现了模式的彻底分解。
通过不断投影分解,提高范式等级,可以消除一系列异常,但是随之而来的问题是查询操作会变得越来越复杂。理论上一般分解到 3NF 即可。