数据库逻辑设计模式规范化

关系模式基本概念

要建立一套规范化理论,需要研究系统下各组成部分之间的关系,数据库表中主要是属性间的关系。关系模式中的属性之间相互依赖、相互制约的联系称为数据依赖。举一个简单的例子,关系模式 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->YY!->XY->Z,则称 Z 对 X 传递函数依赖;
  • 直接函数依赖,X->Y, Y->XY->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 即可。