当前位置:首页 > 演讲稿 > 数据库-关系模式的设计-规范化:关系模式规范化设计的基本思想
 

数据库-关系模式的设计-规范化:关系模式规范化设计的基本思想

发布时间:2019-08-03 09:52:32 影响了:

关系数据库设计

目录

第1章 简介 .............................................................................................................................. 1

第2章 函数依赖 ...................................................................................................................... 1

2.1 函数依赖的定义 .......................................................................................................... 1

2.2 关系的键码 .................................................................................................................. 2

2.3 超键码 .......................................................................................................................... 3

2.4 函数依赖规则 .............................................................................................................. 3

2.4.1 分解/合并规则 ................................................................................................ 3

2.4.2 平凡依赖规则 .................................................................................................. 3

2.4.3 传递规则 .......................................................................................................... 4

第3章 模式设计 ...................................................................................................................... 4

3.1 问题的提出 .................................................................................................................. 4

3.2 问题的根源 .................................................................................................................. 5

3.2.1 完全依赖和部分依赖 ...................................................................................... 5

3.2.2 传递依赖 .......................................................................................................... 6

3.3 解决的途径 .................................................................................................................. 7

3.3.1 第1范式(1NF ) ............................................................................................ 7

3.3.2 第2范式(2NF ) ............................................................................................. 7

3.3.3 第3范式(3NF ) ............................................................................................. 8

3.3.4 BC范式(BCNF ) ............................................................................................ 8

3.4 分解的原则 .................................................................................................................. 9

3.5 分解的方法 ................................................................................................................ 12

3.5.1 模式分解的两个原则 ...................................................................................... 12

3.5.2 模式分解的3种方法 ...................................................................................... 13

3.5.3 把关系模式分解成BC 范式的方法总结 . ...................................................... 14

3.6 关系模式规范化小结 ................................................................................................ 15

第4章 多值依赖 .................................................................................................................... 16

4.1 属性独立性带来的冗余 ............................................................................................ 16

4.2 多值依赖的定义 ........................................................................................................ 17

4.3 第4范式 .................................................................................................................... 18

4.4 分解成第4范式 ........................................................................................................ 18

第5章 总结 ............................................................................................................................ 19

第1章 简介

关系数据库是由一组关系组成,所以关系数据库的设计归根到底是如何构造关系,即如何把具体的客观事物划分为几个关系,而每个关系又有哪些属性组成。在我们构造关系时,经常会发现数据冗余和更新异常等现象,这是由于关系中个属性之间的相互依赖性和独立性造成的。

关系模型有严格的数学理论基础,并形成了关系数据库的规范化理论,这为我们设计出合理的数据库提供了有利的工具。

第2章 函数依赖

2.1 函数依赖的定义

为了便于了解函数依赖(functional dependency)的概念,先看一个具体的关系实例。 例:考虑学生关系Student ,该关系中涉及的属性包括学生的学号(Sno )、姓名(Sname )、所在系(Sdept )、系主任姓名(Mname )、课程名(Cname )和成绩(Grade )。学生关系Student 的实例如表1所示。

表 1 学生关系Student 实例

在这个实例中,我们可以看到属性之间存在某些内在的联系:

由于一个学号值对应一个学生,一个学生只在一个系,因而当“学号”确定之后,姓名及所在系也就唯一确定了。属性中的这种依赖关系类似于数学中的函数。因此说Sno 函数决定Sname 和Sdept ,或者说Sname 和Sdept 函数依赖于Sno ,记作Sno →Sname ,Sno →Sdept 。

下面给出函数依赖的严格定义:如果关系R 的两个元组在属性A 1,A 2,„A n 上一致(也就是,两个元组在这些属性所对应的各个分量具有相同的值),则它们在另一个属性B 上也一致。那么,我们就说在关系R 中属性B 函数依赖于属性A 1A 2„A n 。这种

依赖正式记作A 1A 2„A n →B ,也就是说“A 1,A 2,„A n 函数决定B ”。其中,A 1A 2„A n 称为决定因素。

如果一组属性A 1,A 2,„A n 函数决定多个属性,比如说:

A 1A 2„A n →B 1

A 1A 2„A n →B 2

A 1A 2„A n →B m

则可以把这一组依赖关系简记为:

A 1A 2„A n →B 1B 2„B m

例:在上例中,我们可以列举关于Student 关系的以下四个函数依赖:

Sno →Sname

Sno →Sdept

Sdept →Mname

Sno Cname→Grade

由于前面的两个依赖的左边完全相同,都是Sno ,用简写的形式可以把它们汇总在一行中:

Sno →Sname Sdept

根据函数依赖的传递规则,从Sno →Sdept 和Sdept →Mname 可以导出Sno →Mname 。这一点我们从感性认识上也很容易理解,一个学号对应唯一的学生,而一个学生只能有唯一的系主任。

另一方面,Sno →Cname 就是错误的,它不是函数依赖,原因显而易见,如第1元组和第2元组,它们的Sno 分量相同,但Cname 分量却不同。

2.2 关系的键码

我们已经了解了键码的概念,下面从函数依赖角度给出定义。

如果一个或多个属性的集合{A1,A 2,„A n }满足如下条件,则称该集合为关系R 的键码(key ):

(1)这些属性函数决定该关系的所有其他属性。也就是说,R 中不可能有两个不同的元组,它们在A1,A2,„An 上的取值是相同的。

(2){A1,A 2,„A n }的任何真子集都不能函数决定R 的所有其他属性,也就说,键码必须是最小的。

例:在学生的关系中,属性集{Sno,Cname}构成Student 关系的键码。

有时一个关系有多个键码。

例:在Student 关系中我们可以加上属性身份证号(Idno ),则关系中存在两个键码{Sno,Cname}和{Idno,Cname}。

2.3 超键码

包含键码的属性集称为“超键码”(superkey ),是“键码的超集”的简称。因此,每个键码都是超键码。但是,某些超键码不是键码。

例:在学生关系中有许多超键码,不仅键码{Sno,Cname}本身是超键码,而且该属性集的任何超集,如{Sno,Cname ,Grade},{Sno,Sname ,Cname}都是超键码。

2.4 函数依赖规则

假设已知某关系所满足的函数依赖集,在不知道该关系的具体元组的情况下,通常可以推断出该关系必然满足的其他某些函数依赖。

例:如果已知关系R 拥有属性A ,B 和C ,它满足如下函数依赖:A →B 和B →C ,则断定R 也满足依赖A →C 。

下面介绍3个函数依赖规则。

2.4.1 分解/合并规则

(1)我们可以把一个函数依赖A 1A 2„A n →B 1B 2„B m 用一组函数依赖A 1A 2„A n →B i (i=1,2,„,m )来替代。这种转换成为“分解规则”(splitting rule)。

(2)我们也可以把一组函数依赖A 1A 2„A n →B i (i=1,2,„,m )用一个依赖A 1A 2„A n →B 1B 2„B m 来替代。这种转换称为“合并规则”(combining rule)。

2.4.2 平凡依赖规则

对于函数依赖A 1A 2„A n →B 1B 2„B m ,

(1)如果B 是A 的子集,则称该依赖为平凡依赖。

(2)如果B 中至少有一个属性不在A 中,则称该依赖为非平凡的。

(3)如果B 中没有一个属性在A 中,则称该依赖为完全非平凡的。

平凡依赖规则:

函数依赖A 1A 2„A n →B 1B 2„B m 等价于A 1A 2„A n →C 1C 2„C k ,其中C 是B 的子集,但C 不在A 中出现。我们称这个规则为“平凡依赖规则”(trivial dependency rule)。

若函数依赖满足平凡依赖规则,则该依赖为完全非平凡依赖。

2.4.3 传递规则

传递规则使我们把两个函数依赖级联成一个新的函数依赖。

如果A 1A 2„A n →B 1B 2„B m 和B 1B 2„B m →C 1C 2„C k 在关系R 中成立,则A 1A 2„A n →C 1C 2„C k 在R 中也成立。这个规则就称为传递规则(transitive rule)。

第3章 模式设计

关系数据库设计理论主要用于知道数据库的逻辑设计,确定关系模式的划分,每个关系模式所包含的属性从而使得由一组关系模式组成的关系模式作为一个整体,既能客观描述各种实体,又能准确反映各种实体之间的联系,还能实地体现出实体内部属性之间的相互依存与制约。

3.1 问题的提出

在设计数据库模式的时,特别是从面向对象的ODL 设计或从E-R 设计直接向关系数据库转换时,很容易出项的问题是冗余性,即一个事实在多个元组中重复。而且,我们发现造成这种冗余的最常见的原因是,企图把一个对象的单指和多值特性包含在一个关系中。

例:在2.1节,当我们把学生的单指信息(如所在系)和多值特性(如课程集)存储子啊一起的时候,就导致了信息的冗余。

表 2 学生关系Student 实例

当我们企图把太多的信息存放在一个关系中时,就会出现数据冗余和更新异常等问题。主要表现如下:

(1)数据冗余。信息可能在多个元组中不必要的重复。如学生所在的系和系主任。

(2)修改异常。我们可能修改了一个元组的信息,但另一个元组的相同信息却没有修改。比如,计算机系的主任换了一个人,可能由于粗心,只修改了第1元组,而没有修改第2和第3元组。于是出现数据不一致。然而重新设计关系Student 从而出现这

种错误是完全可能的。

(3)删除异常。如果一组属性的值变为空,带来的副作用可能是丢失一些信息。比如,如果我们从学生晓雪的课程集中删除了自动化设计,那么数据库里就没有这个学生的课程信息了。由于课程名和学号共同组成该关系的键码,而建立数据库时,键码属性不能为空,于是,关系Student 中的晓雪的元组就会消失,同时消失的还有与晓雪有关的其他属性信息。

(4)插入异常。刚开学,学生尚未选课,使得键码属性值缺少课程名,结果导致学生的基本情况(学号、姓名、所在系)甚至系主任姓名都不能插入。这显然不符合道理。

3.2 问题的根源

关系的键码函数决定该关系的所有其他属性,由于键码能唯一的确定一个元组,所以,也可以说关系的键码函数决定该关系的所有属性。换句话说,一个关系中的所有属性都函数依赖于该关系的键码。

当我们进一步分析时,就会发现不同的属性在关系模式中所处的地位和扮演的角色是不同的。

再深入分析,又会发现不同的属性对键码函数依赖的性质和程度是有区别的。有的属于直接依赖,有的属于间接依赖(通常称为传递依赖)。当键码由多个属性组成时,有的属性函数依赖于整个键码属性集,而有的属性只函数依赖于键码属性集中的一部分属性。

3.2.1 完全依赖和部分依赖

对于函数依赖W →A ,如果存在V W (V 是W 的真子集)而函数依赖V →A 成立,则称A 部分依赖(partial dependency)于W ,否则,若不存在这种V ,则称A 完全依赖(full dependency)于W 。

从上述定义中可以得出一个结论:若W 为单属性,则不存在真子集V ,所以A 必然完全依赖于W 。

例:我们结合学生关系的例子具体说明完全依赖和部分依赖对冗余或异常有没有影响。关系模式Student (Sno ,Sname ,Sdept ,Mname ,Cname ,Grade )中(Sno ,Cname )为键码,函数依赖集如下:

Sno →Sname ,Sdept

Sdept →Mname

Sno →Mname

P −→Sno ,Cname −Sname ,Sdept ,Mname

F −→Sno ,Cname −Grade

可以看出属性Sname ,Sdept 和Mname 都函数依赖于Sno ,而部分依赖于键码,上面用P 标记。属性Grade 则完全依赖于键码,上面用F 标记。

观察表2关系Student 的实例,就会注意到:

对键码完全依赖的属性Grade 没有任何的冗余,每个学生的每门课程都有特定的成绩(当然,两门课程的成绩完全相同是有可能的,但这并不意味着冗余)。

对键码部分依赖的属性Sname ,Sdept 和Mname 由于只函数依赖于Sno ,因此,当一个学生选修几门课时,这些数据就会多次重复出现,造成大量数据冗余;另一方面,当对一个学生的基本情况(学号、姓名、所在系)进行更新时,又会出现前面讨论过的异常。

从这个例子可以看出,在一个关系模式中,当存在非主属性对键码的部分依赖时,就会产生数据冗余和更新异常。若非主属性对键码完全函数依赖,则不会出现类似问题。

3.2.2 传递依赖

对于函数依赖X →Y ,如果Y ↛X (X 不函数依赖于Y )而函数依赖Y →Z 成立,则称Z 对X 传递依赖(transitive dependency)。

说明:如果X →Y ,且Y →X ,则X ,Y 相互依赖,这时Z 与X 之间就不是传递依赖,而是直接依赖了。实际上,我们以前所讨论的函数依赖大多数是直接依赖。

例:如果学生中没有重名现象,则学号与姓名之间就属于相互依赖,即

Sno →Sname Sname →Sno Sno →Sname

例:我们还是以学生关系为例,先看如下的函数依赖:

Sno →Sdept Sdept →Mname Sno →Mname

由于一个系有很多学生,所以Sdept ↛Sno 。根据传递依赖的定义可知,Mname 传递依赖于Sno 。

从上面的例子中可以看出,关系模式中非主属性对键码的部分传递依赖和传递依赖是产生数据冗余和更新异常的主要根源。在有的关系模式中,还存在主属性对键码的部分依赖或传递依赖,这是产生冗余和更新异常的根源。

然而,从另一个角度又会发现,关系模式中存在所谓多值依赖则是产生冗余和异常的另一个重要根源。

3.3 解决的途径

当我们对产生数据冗余和更新异常的根源进行深入分析以后,就会发现部分依赖和传递依赖有一个共同之处,这就是,二者都不是基本的函数依赖,而都是导出的函数依赖;部分依赖是以对键码的某个真子集的依赖为基础;而传递依赖的基础则是通过中间属性联系在一起的两个函数依赖。

导出的函数依赖在描述属性之间的联系方面并没有比基本的函数依赖提供更多的信息。从这个意义上看,在一个函数依赖集中,导出的依赖相对于基本的依赖而言,虽然形式上多一种描述方式,但本质上完全是冗余的。正是由于关系模式中存在对键码的这种冗余的依赖导致数据库中的数据冗余和更新异常。

找到了问题的所在,也就有了解决的途径——消除关系模式中各属性对键码冗余的依赖。

由于冗余的依赖有部分依赖与传递依赖之分,而属性又有主属性与非主属性之别,于是,从不同的分析与解决问题的角度出发,导致解决问题的深度和效果会有不同,因此,把解决的途径分为几个不同的级别,以属于第几范式来区别。

所谓范式就是符合某一种级别的关系模式的集合。关系数据库中的关系模式必须满足一定的要求,满足不同程度要求的模式属于不同范式。目前主要有6中范式:第1范式、第2范式、第3范式、BC 范式、第4范式、第5范式。第1范式需满足的要求最低,在第1范式基础上满足进一步要求的为第2范式、,其余以此类推。

各级范式之间存在如下联系:

1NF ⊃2NF ⊃3NF ⊃BCNF ⊃4NF ⊃5NF

通过分解把属于低级范式的关系转换为几个属于高级范式的关系模式的集合,这一过程称为范式化(normalization )。

3.3.1 第1范式(1NF )

如果一个关系模式R 的所有属性都是不可分的基本数据项,则这个关系属于第1范式。

在任何一个关系数据库系统中,第1范式是对关系模式的一个最起码的要求。不满足第1范式的数据库模式就不能称之为关系数据库。

3.3.2 第2范式(2NF )

如关系模式R 属于第1范式,且每个非主属性都完全依赖于键码,则R 属于第2范式。

第2范式不允许关系模式中的非主属性部分依赖于键码。

3.3.3 第3范式(3NF )

若关系模式R 属于第1范式,且每个非主属性都不传递依赖于键码,则R 属于第3范式。

说明:属于第3范式的关系模式必然属于第2范式。因为可以证明部分依赖蕴含着传递依赖。

设A 是关系模式R 的一个非主属性,K 是R 的键码,且K →A 是部分依赖,则A 必然函数依赖于K 的某个真子集K" ,即K" →A 。因为K" K, 所以K →K" (平凡依赖)但K" ↛K 。从K →K" 和K" →A 可知K →A 是传递依赖。因此,可把部分依赖看作是传递依赖的特例。按这样的理解学生关系模式的函数依赖集又可以写成如下形式:

Sno ,Cname →Sno Sno →Sname ,Sdept ,Mname

Sdept →Mname Sno ,Cname →Grade

当按第3范式的要求把所有传递依赖都消除时,也应该把部分依赖消除。换句话说,若关系模式R 属于第3范式,则每个非主属性对于键码既不存在部分依赖,也不存在传递依赖。

例:关系模式STC (Sname ,Tname ,Cname ,Grade ),其中4个属性分别为学生姓名、教师姓名、课程名和成绩。每个学生可选几门课。每个教师只教一门课,但一门课可有几个教师开设。当某个学生选定某门课后,其上课教师就固定了。我们可由上面的语义得到如下的函数依赖:

Sname ,Cname →Tname

Sname ,Tname →Cname

Tname →Cname

该关系有两组属性为键码,{Sname,Cname}和{Sname,Tname}。该关系只有一个非主属性Grade ,又只函数依赖于键码,因此,关系模式STC 属于第3范式。

把关系分解到第3范式,可以在相当程度上减轻原关系中的异常和信息冗余,但也不能保证完全消除关系模式中的各种异常和信息冗余。要想使性能得到进一步改善,就要吧关系模式进一步规范化。

3.3.4 BC 范式(BCNF )

若关系模式R 属于第1范式,且每个属性都不传递依赖于键码,则R 属于BC 范式。

从定义可以看出,BC 范式既检查主属性又检查非主属性,显然比第3范式限制更

Sname ,Cname →Grade Sname ,Tname →Grade

严。当只检查非主属性而不检查主属性时,就成了第3范式。因为可以说任何满足BC 范式的关系都必然满足第3范式。

例:下面有3个关系模式,判别一下它们是否满足BC 范式。

Student (Sno ,Sname ,Ssex ,Sage ,Sdept )

Course (Cno ,Cname ,Ccredit )

SC (Sno ,Cno ,Grade )

第1个关系模式是关于学生学号、姓名、性别、年龄和所在系等信息;第2个关系模式是关于课程的课程号、课程名和学分等信息;第3个关系模式是关于学生选课的信息,包括学号、课程号和该课的成绩。

第1个关系模式中,由于学生有可能重名,因此它只有一个键码Sno ,且只有一个函数依赖Sno →Sname Ssex Sage Sdept,符合BC 范式的条件,所以关系Student 满足BC 范式。

第2个关系模式中,假设课程名具有唯一性,因此该关系中有两个键码分别为Cno 和Cname ,而且函数依赖集为Cno →Cname ,Cno →Ccredit ,Cname →Ccredit ,不难验证,关系Course 满足BC 范式。

第3个关系模式中,键码为{Sno,Cno},函数依赖集为Sno Cno →Grade ,因此关系SC 也满足BC 范式。

3.4 分解的原则

对关系模式进行分解的目的是使模式更加规范化,从而减少以至消除数据冗余和更新异常。但是在关系模式中的诸多属性进行分解的时候,应该注意什么,如何判别不同分解的优劣?

例:我们先举一个模式分解的例子,首先分析上面介绍的关系模式STC (Sname ,Tname ,Cname ,Grade ),其函数依赖集为:

Sname ,Cname →Tname ,Grade

Sname ,Tname →Cname ,Grade

Tname →Cname

键码为{Sname,Cname}和{Sname,Tname}。因为Cname 为主属性,且函数依赖Tname →Cname 的决定因素Tname 只是键码的一部分而不包含键码,所以该模式不属于BC 模式。

我们可以把关系模式STC 分解成SC (Sname ,Cname ,Grade )和ST (Sname ,Tname )。

分解后,SC 中的函数依赖为:

Sname ,Cname →Grade

键码为{Sname,Cname}。对于ST 来说,由于一个学生可选多门课,从而面对多位教师,而一个教师显然要教多个学生,因此学生与教师之间的联系为多对多的,不存在函数依赖。于是ST 中的两个属性共同构成键码。

从上面的分析可知,SC 和ST 都属于BC 范式。至此,似乎已经万事大吉。然而,这样的结论能否经得起检验呢?我们不妨通过实例仔细分析一下。关系模式STC 的实例如下:

表 3 关系模式STC

分解后关系模式ST 的实例如下:

表 4 关系模式ST

分解后关系模式SC 的实例如下:

表 5 关系模式SC

当我们要查询某位教师上什么课时,就要对ST 和SC 两个关系以Sname 为公共属性进行自然连接,这时得到的实例如下:(仅列出了前4个元组)

表 6 ST、SC 自然连接后得到的关系

我们竟然发现“白捡了”许多元组。然而,这不值得庆幸。因为稍加分析,就会意识到,这些“白捡”的元组都是假冒伪劣的,之所以如此是由于丢失了函数依赖Tname →Cname 。按现在的实例,一个教师可能开了几门课。而这是与原来的语义相违背的。原来,在模式分解时把相关的两个属性分开了,即使以后连在一起,有些内在的联系已不能再现了。

从上面的例子可以看出,对模式的分解显然不是随意的。主要涉及两个原则: 1. 无损连接

当关系模式R 进行分解时,R 的元组将分解在相应属性集进行投影而产生新的关系。如果对新的关系进行自然连接得到的元组的集合与原关系完全一致,则称为无损连接(lossless join)。

上面对关系模式STC 进行的分解通过自然连接产生了大量的“伪”元组,形式上元组增多了,但失去了真实性,丢失了信息,属于有损连接。像这样的模式分解显然是不妥的。

无损连接反映了模式分解的数据等价原则。 2. 保持依赖

当对关系R 进行分解时,R 的函数依赖集也将按相应的模式进行分解。如果分解后总的函数依赖集与原函数依赖集保持一致,则则称为保持依赖(preserve dependency )。

上面对关系模式STC 所进行的分解,由于把函数依赖Tname →Cname 所涉及的两个属性分别放在SC 和ST 两个模式中,从而使该依赖丢失了。

保持依赖反映了模式分解的依赖等价原则。依赖等价保证了分解后的模式与原有的模式在数据语义上的一致性。比如,刚才对模式STC 所做的分解,由于丢失了函数依赖Tname →Cname ,就不能再体现一个教师只开一门课的语义了。

数据等价和依赖等价是模式分解的两个最基本的原则。对关系模式进行分解,使之属于第2、3范式,只要采用规范的方法,既能实现无损连接,又能实现保持依赖。然而,要使分解后的模式属于BC 范式,即使采用规范的方法,也只能保持无损连接,而不能绝对的保持依赖。

实际上,在模式分解时,除考虑数据等价和依赖等价之外,还要考虑效率。当我们对数据库的操作主要是查询而更新较少时,为了提高效率,可能宁愿保留适当的数据冗余,让模式中的属性多些,而不愿把模式分解的太小,否则为了查询一些数据,常常要做大量的连接运算,把多个关系连在一起才能从中找到相关的数据,把关系一再连接,花费大量时间,或许得不偿失。因此,保留适当冗余,达到以空间换时间的目的,这也是模式分解的一个重要原则。

所以在实际应用中,对模式分解的要求并不一定要达到BC 范式,有时达到第3范式就足够了。

3.5 分解的方法

关系模式分解的基础是键码和函数依赖。当我们对关系模式中属性之间的内在联系做了深入、准确地分析,确定了键码和函数依赖之后,模式分解因有章(规则)可循,有法(方法)可依而显得简单明了。 3.5.1 模式分解的两个原则

1. 公共属性共享

要把分解后的模式连接起来,公共属性是基础若分解时模式之间未保留公共属性,则只能通过笛卡尔积相连,导致元组膨胀,真实信息丢失,结果失去价值。保留公共属性,进行自然连接是分解后的模式实现无损连接的必要条件。

若存在对键码的部分依赖,则作为决定因素的键码的真子集就应该作为公共属性,用来把分别存在部分依赖(指在原来关系)和完全依赖的两个模式自然连接在一起。

若存在对键码的传递依赖,则传递依赖的中间属性就应作为公共属性,用来把构成传递的两个基本链所组成的模式自然连接在一起。

2. 相关属性合一

把以函数依赖的形式联系在一起的相关属性放在一个模式中,从而使原有的函数依赖得以保持。这是分解后的模式实现保持依赖的充分条件。然而,对于存在部分依赖或传递依赖的相关属性则不应该放在一个模式中,因为这正是导致数据冗余和更新异常的根源,从而也正是模式分解所要解决的问题。

如果关系模式中属性之间的联系错综复杂、交织在一起,难解难分,顾此失彼,也难免会出现分解后函数依赖丢失的现象,这时也只能权衡主次,决定取舍。

分解后的两个模式R1和R2能实现无损连接的充要条件是:

(R 1⋂R 2)→(R 1-R 2)或(R 1⋂R 2)→(R 2-R 1)

上式表明:若分解后的两个模式的交集函数决定两个模式的差集之一,则必然实现无损连接。当我们按上述两个规则对模式进行分解时,两个模式的交集则为公共属性,而两个模式的差集之一为某个函数依赖的右边,因此必然函数依赖于公共属性,从而满足无损连接的充分必要条件。 3.5.2 模式分解的3种方法

1. 部分依赖归子集;完全依赖随键码

要使不属于第2范式的关系模式“升级”,就要消除非主属性对键码的部分依赖。解决的办法就是对原有模式进行分解。分解的关键在于:找出对键码部分依赖的非主属性所依赖的键码的真子集,然后把这个真子集与所有相应的非主属性组合成一个新的模式;对键码完全依赖的所有非主属性则与键码组合称另一个新模式。

例:下面看另一钟学生选课关系模式SC (Sno ,Sname ,Ssex ,Sage ,Cno ,Cname ,Grade ),其中七个属性分别为学生的学号、姓名、性别、年龄、课程号、课程名和成绩。假设学生有重名,而课程名也有可能重名,如几个老师同时给几个班上英语课,则用课程号相区别。键码为{Sno,Cno},函数依赖集如下:

Sno →Sname , Ssex , Sage

F Sno , Cno −−→Grade

Cno →Cname

P

Sno , Cno −−→Cname

P

Sno , Cno −−→Sname , Ssex , Sage

按照完全依赖和部分依赖的概念,可以看出Grade 完全依赖于{Sno,Cno};Sname ,Ssex ,Sage 函数依赖于Sno ,而对于{Sno,Cno}只是部分依赖;同样,Cname 对于{Sno,Cno}也是部分依赖。

找出部分依赖及所依赖的真子集以后,对模式进行分解已是水到渠成。本例中有两个部分依赖,一个完全依赖,结果原来模式一分为三:

SC 1(Sno ,Sname ,Ssex ,Sage ) SC 2(Cno ,Cname ) SC 3(Sno ,Cno ,Grade )

稍加分析就已经明了:上面3个模式均属于BC 范式。实际上,在分解不太复杂的关系模式时,未必要“逐步升级”,一步到位是常有的。

2. 基本依赖为基础,中间属性作桥梁

要使不属于第3范式的关系模式“升级”,就要消除非主属性对键码的传递依赖。解决的办法非常简单:以构成传递链的两个基本依赖为基础形成两个新的模式,这样既切断了传递链,又保持了两个基本依赖,同时又有中间属性作为桥梁,跨越两个新的模

式,从而实现无损的自然连接。

读者可能注意到,我们在前面遇到有关传递依赖的问题其实就是这样解决的。现在加以总结,思路会更加清晰。

在这里强调一点:上面介绍的解决部分依赖和传递依赖的模式分解方法均为既能无损连接,又能保持依赖的规范化方法。

3. 找违例自成一体,舍其右全集归一;若发现仍有违例,再回首如法炮制 要使关系属于BC 范式,既要消除非主属性对键码的部分和传递依赖,又要消除主属性对键码的部分依赖和传递依赖。

分解关系模式的基本方法是:利用违背BC 范式的函数依赖来指导分解过程。我们把违背BC 范式的函数依赖称为BC 范式的违例,简称为违例。

既能关系模式R 不属于BC 范式,就至少能找到一个违例。我们就以违例为基础,把该违例涉及到的所有属性(包括该违例的决定因素以及可以加入该违例右边的所有属性)组合成一个新的模式;从属性全集中去掉违例的右边,也就是,原来模式的属性全集与违例右边(包括可以加入该违例右边的所有属性)的差集则组合成另一个新模式。 3.5.3 把关系模式分解成BC 范式的方法总结

设属性模式为R (A ,B ,C ),其中A ,B ,C 均为属性集,若存在违背BC 范式的函数依赖A →B ,则可以以BC 范式的违例为基础把关系模式分解为:

(1){A,B}

(2){A,C}或{R—B}

例:下面介绍如何利用BC 范式的违例来分解关系模式STC 。在分析前面列出的函数依赖时,我们会发现如下函数依赖就是BC 范式的违例:

Tname →Cname

由于决定因素Tname 值函数依赖于Cname 而无其他属性,因此该函数依赖(违例)右边并无属性可加。于是分解后的第1个关系模式就是:

{Tname,Cname}

另一个模式除含有Tname 以外,还含有Cname 以外的其他属性,也就是含有Sname 和Grade 。于是得到分解后的第2个模式:

{Tname,Sname ,Grade}

可以看出,这两个模式都属于BC 范式。当我们把2个关系以Tname 为公共属性进行自然连接时,不会产生“白捡”元组的现象。

事实上,以BC 范式的违例为基础进行模式分解,最终得到的属于BC 范式的关系

模式都能实现无损连接,但未必能保持函数依赖。

对于函数依赖关系复杂的关系模式,分解一次后,可能仍有BC 范式的违例,只要按上述方法继续分解,模式中的属性总是越分越少,最终少到只有两个属性时,必然属于BC 范式。

如果用两个模式的无损连接的充分必要条件来检验上述的3钟分解方法,就会注意到,这三种方法都保留了公共属性;都有一个模式所依据的函数依赖其决定因素为公共属性,从而使充分必要条件得到满足。

我们用上面的例子说明如下: 方法1: SC 1∩SC 3={Sno}

SC 1—SC 3={Sname,Ssex ,Sage}

Sno →Sname ,Ssex ,Sage

SC 2∩SC 3={Cno} SC 2—SC 3={Cname} Cno →Cname

需说明的是,原来分解时一步到位,直接分解成三个模式,而上述充分必要条件是对分解为两个模式的判断法则,此处按两两相连检验之。

方法2:比如{A→B ,B →C},分解为{A,B}和{B,C},交集为B ,差集之一为C ,B →C 成立。

方法3:分解为{Tname,Cname}和{Tname,Sname ,Grade},交集为Tname ,差集之一为Cname ,Tname →Cname 成立。

第3范式和BC 范式都是以函数依赖为基础来衡量关系模式规范化的程度。 如果一个关系数据库中的所有关系模式都满足第3范式,则已在很大程度上消除了更新异常和信息冗余,但由于可能存在主属性对键码的部分依赖和传递依赖,因此关系模式的分解仍不够彻底。

如果一个关系数据库的所有关系模式都满足BC 范式,那么在函数依赖范畴内,它已实现了模式的彻底分解,达到了最高的规范化程度,消除了更新异常和信息冗余。

3.6 关系模式规范化小结

第1范式是关系模式的基础,若不满足第1范式的条件,则不能称其为关系模式,因此,在通常的讨论中,即使未明确指出关系模式属于第1范式,也应认为尽在不言中。

对键码和函数依赖的分析是判别第2范式、第3范式和BC 范式的基础。在分析函数依赖的基础上找出关系的键码,从而把属性分为主属性和非主属性。第2、第3范式

只检查非主属性与键码之间的函数依赖关系。BC 范式则检查每个函数依赖,而不分主属性和非主属性。最后给出关系模式规范化流程图:

从函数依赖的角度来看,关系模式规范化的基本思路就是从非主属性到主属性逐步消除决定因素不是键码的非平凡依赖,从而使每个决定因素都包含键码(而不是键码的一部分)。

第4章 多值依赖

“多值依赖”(multivalued dependency),指的是两个属性或属性集相互独立。这种情况是函数依赖概念的广义形式,意味着每个函数依赖都包含一个相应的多值依赖。然而,涉及属性集独立性的某些情况,不能解释为函数依赖。在本章我们将寻找产生多值依赖的原因,介绍如何把多值依赖用于数据库模式设计。

4.1 属性独立性带来的冗余

有时会遇到这样的情况,我们设计一个关系模式并发现它满足BC 范式,但该关系依然有和函数依赖无关的某种冗余。模式属于BC 范式的关系中存在冗余,最常见的原因是,当我们直接把ODL 模式转换成关系模式时,某个类的两个或多个属性的独立性。

例:假设关系Undergraduate (简记为U )的定义中包含大学生本科生的姓名,所参加的体育代表队,代表队的级别,所选课的名称和上课地点。下面,我们给出了从关系定义直接得到的某些可能的元组作为关系U 的实例。

表 7 关系Undergraduate

我们注意到关系U 的实例中刘平参加了两个体育队,选了3门课。把一个体育队和一门课相连,而不和另一门课相连,是毫无道理的。因此,表示体育队和课程都是刘平的独立特性的唯一方法就是让每个体育队都和每门课一起出现。但如果在所有的组合中重复体育队和课程信息时,显然存在冗余。实例中,与刘平有关的每个体育队重复了3次,每门课重复了2次。

然而,关系模式U 中却没有BC 范式的违例。因为事实上,模式中根本没有平凡依赖。键码{Uname,Tname ,Tlevel ,Cname ,Caddr},没有那个属性由其他四个属性决定。因为一个学生有可能在不同的教室上同一门课,也可能在同一个教室里上不同的课;同样一个学生既可以参加校级别的足球队也可以参加系级别的足球队,当然也可以同时参加校或系级别的足球队和游泳队。

4.2 多值依赖的定义

假设关系模式为R (A ,B ,C ),其中A ,B ,C 均为属性(集)。如果在A 上取特定值,而在B 上取值的集合与在C 上取值的集合无关,则称多值依赖A →→B 在R 中成立。多值依赖A →→B 可称为A 多值决定B 或B 多值依赖于A 。

例:在前面的例子中,当姓名为刘平时,在级别和体育队的取值的集合(校游泳队;系足球队)与在课程和上课地点的取值的集合(英语,三教101;数学,四教206;计算机三教301)无关,于是多值依赖Uname →→Tname Tlevel。

对于多值依赖,也可以通过具体的元组来表述:如果对于关系R 在A 的所有属性取值一致的每对元组t 和u ,我们可以在R 中找到某个元组v ,满足:

(1)和t ,u 在A 上取值一致。 (2)和t 在B 上取值一致。

(3)和u 在除了A 和B 之外R 的所有属性上取值一致。 则我们这个多值依赖成立。

例:在关系模式U 中,我们就遇到了一个多值依赖,可以表示成: Uname →→Tname Tlevel

即对于每个学生的姓名,所参加的体育队与级别伴随着该学生所选课与上课地点出现。

对于关系U 的实例,如果假设第1个元组为t ,第6个元组为u ,则多值依赖断言

我们在关系U 中必然可以找到一个元组v ,其中Uname 属性为刘平,Tname 和Tlevel 取值与第1个元组一致,而其他属性(Cname 和Caddr )取值与第6个元组一致。的确有这样一个元组:它就是关系U 的实例中的第3个元组。

4.3 第4范式

如果把多值依赖用于新的关系分解算法中,那么在前面发现的由多值依赖引起的冗余是可以消除的。在第4范式(4NF )里,随着违背BC 范式的所有函数依赖的消除,所有的“非平凡”多值依赖也都消除了。

如果符合下述条件:

(1)B 中的属性都不在A 中。 (2)A 和B 并未包含R 的所有属性。

则关系R 的多值依赖A 1A 2„A n →→B 1B 2„B m 就是“非平凡的”。

若关系模式R 属于第1范式,且每个非平凡多值依赖的决定因素都包含键码,则R 就属于第4范式。

例如上述的关系U 就违背了第4范式的条件,如 Uname →→Tname Tlevel

是平凡的多值依赖,但Uname 本身不是键码,所以,关系U 不属于第4范式。 第4范式实际上是BC 范式的广义形式。每个函数依赖也是一个多值依赖。因此,每个BC 范式的违例也是一个第4范式的违例。也就是说,属于第4范式的每个关系都必然属于BC 范式。反过来则不一定正确,想关系U 就是一个实例。

4.4 分解成第4范式

第4范式的分解算法与BC 范式的分解算法非常类似。

首先,我们找一个第4范式违例A →→B ,这个违例可能的确是一个多值依赖,也可能是从相应的函数依赖导出的多值依赖,因为每个函数依赖都是一个多值依赖。

然后,我们把含有第4范式违例的关系R 模式分解成两个模式: (1)A 和B 中的属性;

(2)A 中的属性以及不属于A 也不属于B 的R 的所有其他属性。 例:对于关系U ,按照上面的步骤,我们先找一个第4范式的违例, Uname →→Tname Tlevel

上面的分解规则告诉我们,可用两个新模式来代替原来的关系模式。其中一个模式

U 1只包含上面的多值依赖所涉及的3个属性,另一个模式U 2由该依赖的左边,即Uname ,加上未在该多值依赖中出现的属性组成。这些属性是Cname 和Caddr 。所以,这两个模式分别为:

{Uname,Tname ,Tlevel} {Uname,Cname ,Caddr}

这就是分解的结果。分解后的每个模式中都没有非平凡多值依赖,注意, Uname →→Tname Tlevel和Uname →→Cname Caddr

都不是非平凡多值依赖,因为它们都包含了各自关系模式中的所有的属性。既能不存在非平凡多值依赖也就不存在第4范式的违例,所以它们都属于第4范式。分解后关系U 1和U 2的实例如下所示:

表 8 关系U

表 9 关系U

从这个例子可以看出,把具有多值依赖的关系模式分解后,多值依赖仍成立,只是由非平凡多值依赖变为平凡多值依赖。

把关系模式分解成第4范式的方法可归纳如下:

设关系模式为R (A ,B ,C ),其中A ,B ,C 均为属性集,若存在违背第4范式的非平凡多值依赖A →→B ,则可以以第4范式的违例为基础把关系模式分解为:

(1){A,B}

(2){A,C}或{R—B }

当然,分解成第4范式的过程需要多次分解,但是每一步分解所得的模式的属性数目都绝对比分解前更少,因此,最终我们将得到不需要进一步分解的模式,即它们都属于第4范式。

第5章 总结

本教程主要讨论在关系数据库的设计过程中,为了减少数据冗余,避免出现异常,该如何对数据库模式进行重新设计。为此,本教程介绍了一个重要的概念——函数依赖。

在讨论关系模式规范化的时候,我们介绍了几种范式。其中第1范式到BC 范式的分析主要是函数依赖范畴中;第4范式用到多值依赖的概念;还没有介绍的第5范式将涉及到连接依赖——它和函数依赖及多值依赖一样,也是数据依赖的一种。

函数依赖和多值依赖是两种最重要的数据依赖。如果只考虑函数依赖,则属于BC 范式的关系模式已经很完美了。如果考虑多值依赖,则属于第4范式的关系模式已经很完美了。函数依赖是多值依赖的一种特殊情况,而多值依赖是连接依赖的一种特殊情况。到目前为止,第5范式是最终范式。我们不打算详细讨论连接依赖和第5范式,有兴趣的读者可以参考有关书籍。

最后对本教程的一些重要概念作如下归纳总结:

(1)函数依赖(functional dependency):如果关系R 中的两个元组在某个特定的属性集A 上一致,则它们在某个其他特定属性B 上也一致,我们就称B 与A 之间的关系为函数依赖。具体的说,就是B 函数依赖于A ,或者A 函数决定B 。

(2)键码(key ):关系R 中能函数决定该关系所有其他属性的最小属性集称为关系R 的键码。即键码的任何真子集都不能函数决定该关系的所有其他属性。

(3)属性的封闭集(closure of attribute):对于给定的函数依赖集S ,属性集A 函数决定的属性的集合称为属性集A 在依赖集S 下的封闭集。可利用各种属性组合的封闭集确定关系的键码。

(4)规范化(normalization ):通过模式分解把属于低级范式的关系转换为几个属于高级范式的关系模式的集合,这一过程称为规范化。

(5)第2范式(2NF ):若关系模式R 属于第1范式,且每个非主属性都完全依赖于键码,则R 属于第2范式。要使关系模式属于第2范式,就要消除非主属性对键码的部分依赖。

(6)第3范式(3NF ):若关系模式R 属于第1范式,且每个非主属性都不传递依赖于键码,则R 属于第3范式。因为部分依赖是传递依赖的特例,所以要使关系模式R 属于第3范式,既要消除非主属性对键码的部分依赖,也要消除非主属性对键码的传递依赖。

(7)BC 范式(boyce-codd normal form ):若关系模式R 属于第1范式,且每个属性都不传递依赖于键码,则R 属于BC 范式。在函数依赖的范畴内,关系模式属于BC 范式即已实现了模式的分解,消除了数据冗余和更新异常。

(8)分解原则:无损连接和保持依赖是对关系模式进行分解的两个基本原则。采用规范的方法,使分解后的模式属于第2或第3范式,既能实现无损连接,又能实现保

持依赖;使分解后的模式属于BC 范式,只能保证无损连接,不能绝对保持依赖。

(9)分解方法:模式分解以键码为中心,以函数依赖为基础,针对部分依赖、传递依赖和BC 范式违例可用3中不同的规范的方法,均能使分解后的模式实现无损连接。

(10)多值依赖(multivalued dependency):设关系模式为R (A ,B ,C ),其中A ,B ,C 均为属性(集)。若B ,C 相互独立,且对A 均有多个取值,我们就把属性B (或

C )和A 之间的这种多值相关性称为多值依赖。这时,在R 中就会B ,C 取值集合的各种可能组合。当用对象定义语言(ODL )定义的类中含义两个或多个多值属性联系时,所转换的关系模式就会存在多值依赖。

(11)第4范式(4NF ):关系模式R 中的非平凡多值依赖意味着把只有间接联系的属性放在一个模式中,会产生数据冗余和更新异常。在BC 范式基础上消除非平凡多值依赖,则R 属于第4范式。用规范的方法分解得到的属于第4范式的模式能实现无损连接。

(12)依赖于联系:函数依赖能描述属性之间多对一的联系(如多个学生在一个系);“多”函数决定“一”或“一”函数依赖与“多”;属性间一对一联系对应相互依赖;多对多联系则不存在函数依赖关系。而多值依赖能部分描述属性之间一对多的联系(如一个系有多个学生);“一”多值决定“多”,或“多”多值依赖于“一”;属性间多对多联系可以多值依赖形式出现(如学生选课,一个学生选多门课);一对一联系则不存在多值依赖关系。对于多对多(m :n )联系来说,当n 减少到1(如限制一个学生最多只能参加一个体育队)时,多值依赖就演变成为函数依赖,因此,可把函数依赖看作是多值依赖的特例。

猜你想看
相关文章

Copyright © 2008 - 2022 版权所有 职场范文网

工业和信息化部 备案号:沪ICP备18009755号-3