问题的提出
有一个很基本的问题尚未涉及:针对一个具体问题,应该如何构造一个适合于它的数据库模式,即应该构造几个关系模式,每个关系由哪些属性组成等。这是数据库设计的问题,确切地讲是关系数据库逻辑设计问题。
实际上设计任何一种数据库应用系统,不论是层次的、网状的还是关系的,都会遇到如何构造合适的数据模式即逻辑结构的问题。由于关系模型有严格的数学理论基础,并且可以向别的数据模型转换,因此,人们就以关系模型为背景来讨论这个问题,形成了数据库逻辑设计的一个有力工具一关系数据库的规范化理论。
规范化理论虽然是以关系模型为背景,但是它对于一般的数据库逻辑设计同样具有理论上的意义。
下面首先回顾一下关系模型的形式化定义。
在第 2 章关系数据库中已经讲过,一个关系模式应当是一个五元组。
R(U, D, DOM, F)
- 关系名 R 是符号化的元组语义。
- U 为一组属性。
- D 为属性组 U 中的属性所来自的域。
- DOM 为属性到域的映射。
- F 为属性组 U 上的一组数据依赖。
由于 D、DOM 与模式设计关系不大,因此在本章中把关系模式看作一个三元组:R
当且仅当 U 上的一个关系 r 满足 F 时,r 称为关系模式 R 的一个关系。
作为一个二维表,关系要符合一个最基本的条件:每一个分量必须是不可分的数据项。满足了这个条件的关系模式就属于第一范式(1NF)
在模式设计中,假设已知一个模式 Sφ,它仅由单个关系模式组成,问题是要设计一个模式 SD,它与 Sφ 等价,但在某些指定的方面更好一些。这里通过一个例子来说明一个不好的模式会有些什么问题,分析这些问题产生的原因,并从中找出设计一个好的关系模式的办法。
在举例之前,先非形式地讨论一下数据依赖的概念。
数据依赖是一个关系内部属性与属性之间的一种约束关系。这种约束关系是通过属性间值的相等与否体现出来的数据间相关联系。它是现实世界属性间相互联系的抽象,是数据内在的性质,是语义的体现。
人们已经提出了许多种类型的数据依赖,其中最重要的是函数依赖(Functional Dependency,FD)和多值依赖(Multi—Valued Dependency,MVD)
函数依赖极为普遍地存在于现实生活中。
比如描述一个学生的关系,可以有学号(Sno)、姓名(Sname)、系名(Sdept)等几个属性。 由于一个学号只对应一个学生,一个学生只在一个系学习。因而当“学号”值确定之后,学生的姓名及所在系的值也就被唯地确定了。 属性间的这种依赖关系类似于数学中的函数 y = f(x),自变量 x 确定之后,相应的函数值 y 也就唯一地确定了。 类似的有 Sname = f(Sno),Sdept=f(Sno),即 Sno 函数决定 Sname,Sno 函数决定 Sdept,或者说 Sname 和Sdept 函数依赖于 Sno,记作 Sno → Sname,Sno → Sdept
[例6.1] 建立一个描述学校教务的数据库,该数据库涉及的对象包括学生的学号(Sno)、所在系(Sdept)、系主任姓名(Mname)、课程号(Cno)和成绩(Grade)。
假设用一个单一的关系模式 Student 来表示,则该关系模式的属性集合为 U={Sno,Sdept,Mname,Cno,Grade)
现实世界的已知事实(语义)告诉我们:
- 一个系有若干学生,但一个学生只属于一个系。
- 一个系只有一名(正职)负责人。
- 一个学生可以选修多门课程,每门课程有若干学生选修。
- 每个学生学习每一门课程有一个成绩。
于是得到属性组 U 上的一组函数依赖 F(如图6.1所示)。
F={Sno → Sdept,Sdept → Mname,(Sno,Cno) → Grade}
如果只考虑函数依赖这一种数据依赖,可以得到一个描述学生的关系模式 Student。
表6.1是某一时刻关系模式 Student 的一个实例,即数据表。
但是,这个关系模式存在以下问题:
(1)数据冗余
比如,每一个系的系主任姓名重复出现,重复次数与该系所有学生的所有课程成绩出现次数相同,如表6.1所示。这将浪费大量的存储空间。
(2)更新异常
由于数据冗余,当更新数据库中的数据时,系统要付出很大的代价来维护数据库的完整性,否则会面临数据不一致的危险。
比如,某系更换系主任后,必须修改与该系学生有关的每一个元组。
(3)插入异常
如果一个系刚成立,尚无学生,则无法把这个系及其系主任的信息存入数据库。
(4)删除异常
如果某个系的学生全部毕业了,则在删除该系学生信息的同时,这个系及其系主任的信息也丢掉了。
鉴于存在以上种种问题,可以得出这样的结论:Student 关系模式不是一个好的模式。
一个好的模式应当不会发生插入异常、删除异常和更新异常,数据冗余应尽可能少。
为什么会发生这些问题呢
这是因为这个模式中的函数依赖存在某些不好的性质。这正是本章要讨论的问题。
假如把这个单一的模式改造一下,分成三个关系模式:
- 学生:S(Sno, Sdept, Sno → Sdept);
- 课程:SC(Sno, Cno, Grade, (Sno,Cno) → Grade):
- 系:DEPT(Sdept, Mname, Sdept → Mname)
这三个模式都不会发生插入异常、删除异常的问题,数据的冗余也得到了控制。
一个模式的数据依赖会有哪些不好的性质,如何改造一个不好的模式,这就是下一节规范化要讨论的内容。
规范化
本节首先讨论一个关系属性间不同的依赖情况,讨论如何根据属性间依赖情况来判定关系是否具有某些不合适的性质,通常按属性间依赖情况来区分关系规范化程度为第一范式、第二范式、第三范式和第四范式等;然后直观地描述如何将具有不合适性质的关系转换为更合适的形式。
6.1 节关系模式 Student 中有 Sno → Sdept 成立,也就是说在任何时刻 Student 的关系实例(即 Student 数据表)中,不可能存在两个元组在 Sno 上的值相等,而在 Sdept 上的值不等。
因此,表 6.2 的 Student 表是错误的。因为表中有两个元组在 Sno 上都等于 S,而 Sdept 上一个为计算机系,一个为自动化系。
函数依赖
:::info
定义6.1 设 R(U) 是属性集 U 上的关系模式,X,Y 是属性集 U 的子集。
若对于关系模式 R(U) 的任意一个可能的关系 r,r 中不可能存在两个元组在 X 上的属性值相等,而在 Y 上的属性值不等,则称 X 函数确定 Y 或 Y 函数依赖于X,记作 X → Y。
:::
函数依赖和别的数据依赖一样是语义范畴的概念,只能根据语义来确定一个函数依赖。
例如,姓名 → 年龄这个函数依赖只有在该部门没有同名人的条件下成立。 如果允许有同名人,则年龄就不再函数依赖于姓名了。 设计者也可以对现实世界作强制性规定,例如规定不允许同名人出现,因而使姓名 → 年龄这个函数依赖成立。这样当插入某个元组时这个元组上的属性值必须满足规定的函数依赖,若发现有同名人存在,则拒绝插入该元组。
注意,函数依赖不是指关系模式 R 的某个或某些关系满足的约束条件,而是指 R 的一切关系均要满足的约束条件。
下面介绍一些术语和记号。【X,Y 是属性集 U 的子集】
- X → Y,但 Y ⊈ X,则称 X → Y 是非平凡的函数依赖。
X → Y,但 Y ⊆ X,则称 X → Y 是平凡的函数依赖。
对于任一关系模式,平凡函数依赖都是必然成立的,它不反映新的语义。 若不特别声明,总是讨论非平凡的函数依赖。
若 X → Y,则 X 称为这个函数依赖的决定属性组,也称为决定因素(determinant)
- 若 X → Y,Y → X,则记作 X ←→ Y。
- 若 Y 不函数依赖于 X,则记作XY。
:::info 定义6.2 在 R(U) 中,如果 X → Y,并且对于 X 的任何一个真子集 X’,都有X’Y,则称 Y 对 X 完全函数依赖,记作: ::: 若 X → Y,但 Y 不完全函数依赖于X,则称 Y 对 X 部分函数依赖,记作:
例6.1 中是完全函数依赖,是部分函数依赖。 因为 Sno → Sdept 成立,而 Sno 是 (Sno, Cno) 的真子集。
:::info
定义6.3 在 R(U) 中,如果 X → Y (Y ⊈ X),YX,Y → Z,Z ⊈ Y 则称 Z 对 X 传递函数依赖。
记为
:::
例6.1 中有 Sno → Sdept,Sdept→Mname 成立,所以
这里加上条件YX,是因为如果Y → X,则X ←→ Y,实际上是,是直接函数依赖而不是传递函数依赖。
码
码是关系模式中的一个重要概念。
在第2章中已给出了有关码的若干定义,这里用函数依赖的概念来定义码。
:::info
定义6.4
设 K 为 R 中的属性或属性组合,若则 K 为 R 的候选码。
:::
注意 U 是完全函数依赖于 K,而不是部分函数依赖于 K。 如果 U 部分函数依赖于 K,则 K 称为超码。 候选码是最小的超码,即 K 的任意一个真子集都不是候选码。
若候选码多于一个,则选定其中的一个为主码。
- 包含在任何一个候选码中的属性称为主属性;
- 不包含在任何候选码中的属性称为非主属性 或 非码属性。
最简单的情况,单个属性是码;
最极端的情况,整个属性组是码,称为全码。
在后面的章节中主码或候选码都简称为码。 读者可以根据上下文加以识别。
[例6.2] 关系模式 S(Sno, Sdept, Sage) 中单个属性 Sno 是码,用下划线显示出来。SC(Sno, Cno, Grade) 中属性组合(Sno, Cno) 是码。
:::info
定义6.5
关系模式 R 中属性或属性组 X 并非 R 的码,但 X 是另一个关系模式的码,则称 X 是 R 的外部码,也称外码。
:::
如在 SC(Sno, Cno, Grade) 中,Sno 不是码,但 Sno 是关系模式 S(Sno, Sdept, Sage) 的码,则 Sno 是关系模式 SC的外码。
主码与外码提供了一个表示关系间联系的手段,如例6.2 中关系模式 S 与 SC 的联系就是通过 Sno 来体现的。
范式
关系数据库中的关系是要满足一定要求的,满足不同程度要求的为不同范式。
- 满足最低要求的叫第一范式,简称 1 NF;
- 在第一范式中满足进一步要求的为第二范式,其余以此类推。
所谓 “第几范式” 原本是表示关系的某一种级别,所以常称某一关系模式 R 为第几范式。
现在则把范式这个概念理解成符合某一种级别的关系模式的集合,即 R 为第几范式就可以写成 R ∈ x NF。
对于各种范式之间的关系有:5NF ⊆ 4NF ⊆ BCNF ⊆ 3NF ⊆ 2NF ⊆ 1NF 成立,如 图6.2 所示。
一个低一级范式的关系模式通过模式分解可以转换为若干个高一级范式的关系模式的集合,这种过程就叫规范化。
2 NF
:::info
定义6.6
若 R ∈ 1NF,且每一个非主属性完全函数依赖于任何一个候选码,则 R ∈ 2NF。
:::
下面举一个不是 2NF 的例子。
[例6.4] 有关系模式 S-L-C(Sno, Sdept, Sloc, Cno, Grade) 其中 Sloc 为学生的住处,并且每个系的学生住在同一个地方。S-LC的码为(Sno,Cno)。则函数依赖有:
- ,
- ,
- (每个系的学生只住一个地方)
函数依赖关系如图6.3所示。
图中用虚线表示部分函数依赖。
另外,Sdept 还函数依赖于 SloC,这一点在讨论第二范式时暂不考虑。
可以看到非主属性 Sdept、Sloc 并不完全函数依赖于码。
非主属性 Sdept、Sloc 完全函数依赖于码中的 sno。 因此可以说,非主属性 Sdept、Sloc 部分函数依赖于码。
因此 S-LC(Sno, Sdept, Sloc, Cno, Grade)不符合 2NF 定义,即 S-L-C ∉ 2NF
一个关系模式 R 不属于 2NF 就会产生以下几个问题:
(1)插入异常
假若要插入一个学生 Sno=S7, Sdept=PHY, Sloc-BLD2, 但该学生还未选课,即这个学生无 Cno,这样的元组就插不进 S-L-C 中。因为插入元组时必须给定码值,而这时码值的一部分为空,因而学生的固有信息无法插入。
(2)删除异常
假定某个学生只选一门课,如 S4 就选了一门课 C3,现在 C3 这门课他也不选了,那么 C3 这个数据项就要删除。而 C3 是主属性,删除了 C3,整个元组就必须一起删除,使得 S4 的其他信息也被删除了,从而造成删除异常,即不应删除的信息也删除了。
(3)修改复杂
某个学生从数学系 (MA) 转到计算机科学系 (CS),这本来只需修改此学生元组中的 Sdept 分量即可,但因为关系模式 S-L-C 中还含有系的住处 Sloc 属性,学生转系将同时改变住处,因而还必须修改元组中的 Sloc 分量。
另外,如果这个学生选修了 k 门课,Sdept、Sloc 重复存储了 k 次,不仅存储冗余度大,而且必须无遗漏地修改 k个元组中全部 Sdept、Sloc 信息,造成修改的复杂化。
分析上面的例子可以发现问题在于有两类非主属性:
- 一类如 Grade,它对码是完全函数依赖;
- 另一类如 Sdept、Sloc,它们对码不是完全函数依赖。
解决该问题的办法是:用投影分解把关系模式 S-L-C 分解为两个关系模式:
- 学生成绩:SC(Sno, Cno, Grade)
- 学生信息:S-L(Sno, Sdept, Sloc)
投影分解投影是:从关系 R 中选取若干属性列组成新的关系的操作。
而投影分解法也就是:从给定关系中投影出某些属性出来组成新的关系,然后这些新关系的总和就是投影分解法分解出来的关系。
关系模式 SC 与 S-L中属性间的函数依赖可以用图6.4、图6.5表示如下。
关系模式 SC 的码为 (Sno, Cno),关系模式 S-L 的码为 Sno,这样就使得非主属性对码都是完全函数依赖了。3 NF
:::info 定义6.7
设关系模式 R ∈ 1NF,若 R 中不存在这样的码 X,属性组 Y 及非主属性 Z (Y ⊈ Z),使得 X → Y,Y → Z成立,YX,则称 R ∈ 3NF。 :::对于这个定义,我不太理解。
由定义6.7可以证明,若R ∈ 3NF,则每一个非主属性既不传递依赖于码,也不部分依赖于码。也就是说,可以证明如果 R 属于 3NF,则必有 R 属于 2NF。
在图6.4中关系模式 SC 没有传递依赖,而图6.5中关系模式 S-L 存在非主属性对码的传递依赖。
在 S-L 中,由 Sno → Sdept(SdeptSno),Sdept → Sloc,可得。
因此 SC ∈ 3NF,而 S-L ∉ 3NF。
一个关系模式 R 若不是 3NF,就会产生与 6.2.4节中 2NF 相类似的问题。
读者可以类比 2NF 的反例加以说明。
解决的办法同样是将 S-L 分解为:
- 学生系信息:S-D ( Sno, Sdept)
- 住处信息:D-L (Sdept, Sloc)。
BC NF
BCNF(Boyce Codd Normal Form)是由 Boyce 与 Codd 提出的,比上述的 3NF 又进了一步,通常认为 BCNF 是修正的第三范式,有时也称为扩充的第三范式。
:::info
定义6.8
关系模式 R ∈ 1NF,若 X → Y 且 Y ⊈ X 时 X 必含有码,则 R ∈ BCNF。
:::
也就是说,关系模式 R 中,若每一个决定因素都包含码,则 R ∈ BCNF。
由 BCNF 的定义可以得到结论,一个满足 BCNF 的关系模式有:
- 所有非主属性对每一个码都是完全函数依赖。
- 所有主属性对每一个不包含它的码也是完全函数依赖。
- 没有任何属性完全函数依赖于非码的任何一组属性。
由于 R ∈ BCNF,按定义排除了任何属性对码的传递依赖与部分依赖,所以 R ∈ 3NF。
严格的证明留给读者完成。但是若 R ∈ 3NF,R 未必属于 BCNF。
下面用几个例子说明属于 3NF 的关系模式有的属于 BCNF,但有的不属于 BCNF。
[例6.6] 属于 BCNF 关系模式 S(Sno, Sname, Sdept, Sage),假定 Sname 也具有唯一性, 那么 S 就有两个码,这两个码都由单个属性组成,彼此不相交。其他属性不存在对码的传递依赖与部分依赖,所以 S ∈ 3NF。同时 S 中除 Sno、Sname 外没有其他决定因素,所以 S 也属于 BCNF。
[例6.8] 不属于 BCNF关系模式 STJ(S, T, J)中,S 表示学生,T 表示教师,J 表示课程。
每一教师只教一门课,每门课有若干教师,某一学生选定某门课, 就对应一个固定的教师。
由语义可得到如下的函数依赖。
- (S, J) → T
- (S, T) → J
- T → J
函数依赖关系可以用图6.6表示,这里(S,J)、(S,T) 都是候选码。
STJ是 3NF,因为没有任何非主属性对码传递依赖或部分依赖,但 STJ 不是 BCNF 关系,因为 T 是决定因素,而 T不包含码。
对于不是 BCNF 的关系模式,仍然存在不合适的地方。读者可自己举例指出 STJ 的不合适之处。
非 BCNF 的关系模式也可以通过分解成为 BCNF。
例如 STJ 可分解为:
- ST(S, T)
- TJ (T, J)
它们都是 BCNF。
3NF 和 BCNF是在函数依赖的条件下对模式分解所能达到的分离程度的测度。
一个模式中的关系模式如果都属于 BCNF,那么在函数依赖范畴内它已实现了彻底的分离,已消除了插入和删除的异常。
3NF 的“不彻底”性表现在可能存在主属性对码的部分依赖和传递依赖。
多值依赖
4 NF
:::info
:::