在前一篇里介绍了关系代数,本节将基于关系代数说明关系数据库设计的理论。其中函数依赖作为基础部分,在模式设计的约束中引入各种范式及其应对的问题。
3.1 函数依赖
关系设计理论使人们可以根据少数简单的原则来检验一个设计并进行改进。设计理论规定了作用在关系上的约束,最常见的约束为函数依赖FD。
3.1.1 FD的定义
关系R上的函数依赖:如果R的两个元组在属性A1,A2, ... , An上一致,那么它们必须在属性B1,B2,...,Bm上也一致,我们称Ai函数决定Bj,形式地记作A1,A2,..,An -> B1,B2,..,Bm。
如果关系R的每个实例都使得一个FD f 为真,则称R满足函数依赖f。
3.1.2 关系的键
如果关系R的属性集t={A1,A2,...,An}是键,则必须满足1) 这些属性函数决定关系所有其他属性,2)在t的所有真子集中,没有一个可以函数决定R的其他属性。概括说来键是最小属性集且函数决定其他属性。如果一个属性集只满足第1个条件,不满足第2个条件,则称其为超键。
若一个关系中有多个键,则要指定其中一个为主键。
3.2 函数依赖的推导和规则
3.2.1 FD的推导
对于关系R,FD有不同的表示方式。记S和T是R的函数依赖集合
S=>T:关系实例在满足S的函数依赖的同时,也满足函数依赖T,但反之不成立。
S和T等价:关系实例在满足S和满足T的情况完全一样。此时有S=>T,且T=>S。
传递性:若存在FD X->Y,Y->Z,则有X->Z。
传递函数依赖:有R(U),若X->Y,Y->Z,不存在Y->X,且Y不是X的真子集,Z不是Y的真子集,则称Z传递依赖于X。
增广性:若存在X->Y,则有XZ->YZ。
3.2.2 分解/结合规则
FD A1,A2,...,An -> B1,B2,...,Bm 等价于一组FD的集合:
(1) A1,A2,...,An -> B1; (2) A1,A2,...,An -> B2; .... , (m) A1,A2,...,An -> Bm。
3.2.3 平凡函数依赖
平凡函数依赖的右边是左边的真子集。形式化的,对于关系R(U),U是属性的全集,有U的子集X和Y,FD X->Y,若Y ⊆ X,则称此FD为平凡函数依赖。反之,则称FD为非平凡的函数依赖。
3.2.4 计算属性集的闭包
若有T={A1,A2,...,An}是属性集合,S={f1,f2,..,fm}是函数依赖的集合,则S集合下属性集合T的闭包记作T+,T+中的每个元素都满足S,且可以由T推断出来。
属性闭包算法:
输入:属性集合T {A1, A2, ..., An} ,FD集合S
输出:闭包{A1,A2,....,An}+
1 如有必要,分解S中的FD,使其右边只有一个属性
2 设D为结果集,并初始化为T
3 从S中寻找FD X->Y 使得 X⊆D 中,而Y不在D中。若找到,将Y加入D中,并重复这一过程。当最终不能有元素再加入D时终止。
4 此时D即为{A1,A2,....,An}+
算法的有效性可以由传递性来导出。
3.2.5 函数依赖的基本集
给定一个FD集合F,任何与F等价的FD集合都称为F的基本集,这里我们只考虑右边为单个属性的FD所组成的基本集。
最小化基本集:1) 所有FD右边均为单一属性 2) 从中删除任意一个FD,此集合不再是基本集 3) 从任意一个FD中删除一个或多人属性,此集合不再是基本集
3.2.6 函数依赖的投影
对于关系R,及其上的FD集合F,若对R进行投影生成新的关系S,则S对应的FD集合F' 称为函数依赖F的投影。F'中的FD满足从F推断而来且只包含S中的属性。
函数依赖集的投影算法:
输入:关系R及其投影S=πL(R),R的FD集F
输出:在S中成立的FD集合
1 令T为待求结果集,初始为空集
2 对于S的每个子集X,计算X+,计算依据FD集合F。对于所有在X+中且属于S的属性A,将所有非平凡FD X->A添加到T中。
3 此时T是S中成立的FD的基本集,但可能不是最小化基本集。通过以下步骤构造T的最小化基本集:(最小基本集算法)
3.1 若T中某个FD能从T中其他FD推断出来,则从T中删除之。
3.2 对于每个FD的左边是多个属性的FD f ,若FD的左边删除一个属性后的新FD f'1 仍能从T中其他FD推断出来,则用f1替代f。
3.3 重复上面两个步骤,直到T不再变化。
3.3 关系数据库模式设计与BCNF范式
3.3.1 异常
不好的设计会产生数据库使用上的异常,其基本类型有冗余(占用大量空间)、更新异常(无法全部更新)、删除异常(删除后导致某些数据丢失)。
一般用分解关系的方法来消除异常。即将一个不合理的关系,分解为多个合理的关系。
3.3.2 BCNF范式
若R属于BCNF当且仅当:R的非平凡FD的左边都是超键。形式化的若R的非平凡FD X->Y,则X为R的超键。
3.3.3 BCNF分解算法
输入:关系R0和其上的函数依赖F0
输出:由R0分解出的关系集合,其中每个关系均属于BCNF
1 设置R=R0,F=F0
2 若R已经是BCNF,若返回{R}
3 若R存在BCNF违例,假设为X->Y。使用属性闭包算法计算X+,选择R1=X+作为关系模式,使用R2包含属性X和不在X+中的属性。
4 使用FD的投影算法计算R1和R2的FD集,分别记为F1和F2。
5 使用本算法递归地分解R1和R2。返回分解得到的结果集合。
3.4 分解的优劣
分解具有三个性质:1 消除异常 2 信息可恢复 3 依赖的保持
上面介绍的BCNF分解可以保持前两条性质,而下节介绍的3NF可以保持后两条性质。事实上,没有办法同时保证这三个性质。
3.4.1 从分解上恢复信息
如果一种连接在分解后,可以通过连接重新获得R,则称此分解含有无损连接。
对于关系R,R的属性集为X U Y U Z,如果有X->Y成立,则R =πx,y(R) ⋈ πx,z(R)。从这条结论上看,BCNF分解算法可以保证分解包含无损连接。
3.4.2 无损连接的chase检验
当一个关系分解含有无损连接时,即πs1(R) ⋈ πs2(R) ⋈ ...⋈πsi(R) = R时,连接结果的每个元组都属于R。
chase检验法:
1) 初始化图表:假设R包含属性A,B...,使用a,b,...来表示元组在对应属性上的分量。如果t在连接结果中,则R中必然存在元组t1,t2,...,tk,使得每个ti在对应的属性集Si上的投影结果的连接为t。由此ti和t在对应关系Si的属性一致,但ti的其他分量未知。对于ti,使用和t相同的字母表示地些Si属性上的分量,若不属于Si,则加下标i。
2) chase过程。使用F中FD来尽可能等同图表中的字母。在等同字母时,如果其中一个是不带下标的,将另一个也变为不带下标的。如果等同两个带不同下标的字母,可以将任一个字母的下标变得和另一个相同。如果发现某一行与t相同,即可以证明连接后为无损。
3.4.3 chase检验的形式化描述
H
|
I
|
J
|
K
|
L
|
|
R1
|
|
b12
|
|
|
b35
|
R2
|
a1
|
a2
|
|
a4
|
b25
|
R3
|
a1
|
b12
|
|
a4
|
b35
|
R4
|
|
b12
|
|
|
b35
|
|
H
|
I
|
J
|
K
|
L
|
R1
|
|
a2
|
|
|
b25
|
R2
|
a1
|
a2
|
|
a4
|
b25
|
R3
|
a1
|
a2
|
|
a4
|
b25
|
R4
|
|
a2
|
|
|
b25
|
3.4.4 依赖的保持
在某些情况下,分解为BCNF后,在无损连接后,得到的一些元组可能不满足原始关系的函数依赖。
3.5 第1-3范式
3.5.1 范式定义
第三范式:关系R是第三范式,当且仅当对于R的非平凡FD,FD的左边要么是超键,要么右边仅由主属性构成。(主属性为键的构成属性)。
第二范式:关系R是第二范式,当且仅当R符合第一范式,且R的非主属性完全函数依赖于R的主属性。
第一范式:关系R的每个元组必须有一个主键,且属性的取值只能为单个值。
从第一范式到BCNF,是对R中非平凡FD的约束增强的一个过程。在1NF约束下,元组可能由多个FD组成,会存在多个不相关的属性。在2NF约束下,将不相关的属性限制为可由各个FD推断的属性。在3NF约束下,更是限制只能有一个FD存在或存在传递依赖。在BCNF约束下,只能存在一个FD。
3.5.2 3NF分解算法
输入:关系R和其FD集F
输出:由R分解出的关系集合,每个关系都属于3NF
1 找到F的一个最小基本集,记为G
2 对于G中的每个FD X->A,将XA作为分解出的一个关系模式Ri
3 若第2步分解得到的关系均不包含R的超键,则增加一个关系,其模式为R的任意一个键
3.6 多值依赖与第四范式
3.6.1 多值依赖MVD
给定关系模式R(U),X,,Y,Z是U的子集,且Z=U-X-Y。若多值依赖X->->Y成立,当用仅当给定一对(x,z)的值有一组Y的值,Y的值仅仅决定于X而与Z不相关。
更精确的,对于R中每个在X属性集上一致的元组t,u,能在R中找到元组v,满足以下条件:1) v在X属性集上与t,u相同 2) v在Y属性集上与 t 相同 3) v在属性集Z上与 u 相同
MVD常常发生在试图把基于X属性两个独立属性集Y,Z合并在单个关系中(两个或以上个1:N关系出现在单个关系中),这就导致关系中需要对Y,Z进行完全配对组合,产生大量冗余。如下面的例子,监护人列仅仅于姓名有关,而与联系方式列无关。
姓名 联系方式 监护人
小明 10000 明爸
小明 20000 明爸
小明 10000 明妈
小明 20000 明妈
3.6.2 多值依赖的推导
平凡MVD:若Y是X的子集,则MVD X->->Y在任何关系中成立。
传递规则:如果MVD X->->Y, Y->->Z,则有X->->Z,Z中属于A的属性要从Z中去掉。
FD提升:FD是MVD,即如果有X->Y,则X->->Y。
互补规则:由MVD的定义,在R上,Z=U-X-Y。如果存在MVD X->->Y,则也存在MVD X->->Z。
附加平凡MVD:对R(U),若U = X U Y,则MVD X ->->Y成立。
3.6.3 第四范式
关系R为4NF,当且仅当,对于R的每个非平凡MVD X ->->Y,其X为超键。
第四范式分解算法:
输入:关系R0(U0),其上的FD和MVD集合F0
输出:由R0分解出来的关系集合,每个关系都属于4NF。分解具有无损连接性质。
1 初始化R(U)=R0,F=F0
2 在F中寻找1个4NF违例,如果不存在,R已为4NF,返回R
3 若存在4NF违例X->->Y,则将R分解为以下两个模式:R1(X,Y),R2(X,U-X-Y)
4 计算R1,R2的投影FD和MVD。根据投影后的依赖集合递归的分解R1和R2。(在3.7节会讨论MVD的投影算法)
例如对于上例,可以分解为两个模式(姓名,联系方式) (姓名,监护人)
3.6.4 范式间的关系
3.7 MVD发现算法
3.7.1 闭包与chase
前面介绍的闭包其实和chase算法本质是相同的。判断X->Y是否可由F推断可基于chase方法如下:
1 初始化图例包含两行,它们仅在属性集X上一致
2 使用F中的FD在图例上执行chase过程
3 若最终的图例在属于Y的所有列上一致,则X->Y成立,否则不成立。
3.7.2 将chase扩展到MVD
将chase的FD推导方法也同样可用来推导MVD。如果要从给定的FD和MVD集中推导出MVD X->->Y,则初始图例要包含两个在X上一致但在所有其他属性上均不同的行。使用给定的FD来等同字母,使用给定的MVD来交换已有的两行中的Y属性的值以产生新行。如果在图例中发现了一个原始元组的Y属性被另一个原始元组的Y属性替换,则可推导出MVD成立。
简单的方法是定义一个目标元组行,并从不改变它。即令目标行的每个分量均为不带下标的字母。初始时,令图例中与X-和Y对应的两个原始行中所有属于X的分量均为不带下标的字母。第一行中所有属于Y的分量也不带下标,第二行中所有不属于X和Y的分量不带下标。这样在chase过程中,只需要观察是否有所有分量均为不带下标字母的行出现在图例中即可。
3.7.3 投影MVD
在将关系分解以后需要计算投影关系的MVD及FD的投影,FD的投影算法之前已有描述。这里可以借用chase方法来在每个分解得到的关系上检验所有的FD和MVD。然而通常不需要对所有MVD进行处理,下面是简化方法:
1 平凡FD和MVD不需要检验
2 对于FD,由于存在合并规则,只需要寻找右边为单个属性的FD
3 如果一个FD或MVD的左边不包含任何给定依赖的左边,则其必定不成立,不需要检验。
参考文献
多值依赖与第四范式 http://en.wikipedia.org/wiki/Fourth_normal_form
数据库系统基础教程 原书第三版 Jeffrey D.Ullman , Jenifer Widom著 机械工作出版社