8.3函数依赖关系功能使用的分解
在8.1节中,我们注意到有一种有一种正式方式用来评估是否一个关系模式应该被分解。这种方式基于键和函数依赖关系的概念。
在讨论关系关系数据库设计的算法时,我们需要谈论关于任意关系和他们的模式,而不只是谈论例子。回顾我们在第二章介绍的关系模型,我们在这里总结我们的表示法。
通常,我们使用希腊字母来表示属性(例如,a)。我们使用小写罗马字母和大写罗马字母letter来表示关系模式(例如,r(R))我们使用表示法r(R)来表明模式是关系r的,R代表属性集,但是有时简单化我们的表示法来使它只在关系名称对我们不重要的时候使用R。
7名对我们确实很重要。当然,一个关系模式是属性集,但不是所有属性集都是模式,当我们使用小写希腊字母是,我们指的是一个属性集可能是架构也可能不是,当我们希望属性集定义为一个模式时一个罗马字母就被使用了.
当一组属性是一个超键时,我们用K来表示它,超键属于特定的关系模式,所以我们使用术语“K是r(R)的超键”.
在我们的例子中,这些名称是真实的(例如,讲师)而在我们的定义和算法中,我们使用单个字母,像r。
一个关系,当然,在任何给定的时间都有一个特定的值,我们将它称为实体,并使用术语(实体r)当我们清楚的看到我们谈论的是一个实体时,我们可以使用简单的关系名称(例如,r1)。
8.3.1键与函数依赖
数据库对现实世界中的一组实体和关系进行建模。在现实世界中,通常对数据有各种各样的约束(规则)。例如,在大学数据库中保存的一些约束是:
1、学生和讲师是独一无二的被ID识别。
2、每个学生和讲师都只有一个名字。
3、每个讲师和学生(主要)只与一个部门相关。
4、每个部门的预算只有一个价值,只有一个相关建筑。
满足所有此类现实约束的关系实例称为关系的法律实例;数据库的法律实例是所有关系实例都是法律实例的实例。
一些最常用的现实世界约束类型可以正式表示为键(超键、候选键和主键),或者作为函数依赖性,我们在下面定义了这些依赖项。
在2.3节中,我们定义了超键的概念,它是一个或多个属性的集合,这些属性集合在一起,允许我们唯一地标识关系中的一个元组。我们在这里重定义如下:让r(R)是一个关系模式。R的子集K是r(R)的子集K,如果在r(R)的任何法律情形下,r(R)的所有元组对ti和T2在r实体中,如果t1≠t2的情况下,则t1【K】≠ t2【K】。也就是说,在关系r(R)的任何法律实体中,没有任何两个元组可能会有相同的值在k的属性集,显然,如果r中没有两个元组在k上有相同的值,那么k在r中独一无二的标识一个元组。
超键是唯一标识一整个元组的的一组属性,函数依赖允许我们表示唯一标识某些属性值的约束。考虑一个关系模式r(R),并让α∈R和β∈R。
·给出了r(R)的一个实例,我们说如果对于所有的元组t1和t2在实例中,则该实例满足函数依赖α→β,例如t1【α】=t2【α】,也满足了t1【β】=t2【β】的函数依赖关系。
·我们认为,如果在r(R)的任何法律实例中,函数依赖α→β满足函数依赖,则它在模式r(R)上保持不变。
利用函数依赖表示法,K是r(R)的一个超键,如果函数依赖K→R保持在r(R)上,换句话说,如果对于r(R)的每一个合法实例,对于实例中的每一对元组t1和t2,只要t1【k】=t2【K】,K就是一个超键,t1【R】=t2【R】(也就是t1=t2)².
函数依赖关系允许我们表达不能有超键解压的约束。在8.1.2节中,我们考虑了模式:
部门表(ID,名称,工资,部门名称,建筑,预算)。
在这里函数依赖关系部门名称→预算保持不变,因为对于每个部门(都被部门名称识别)有一个独一无二的预算金额。
我们表示这一对属性(ID,部门名称)形成了一个超键用于部门表的表达:
ID,部门名称→名称,工资,建筑,预算
我们将用函数依赖关系在两个方面:
1、测试关系实例,以查看它们是否满足给定的函数依赖关系。
2、函数依赖关系。指定对一组法律关系的约束。因此,我们将关注我们自己本身有那些满足给定函数集J依赖的关系实例。如果我们希望约束于模式r(R)上的关系,是满足集合F的函数依赖关系,则说F保持不变在r(R)中。
让我们考虑图8.4关于关系r的实例,看看哪个函数关系满足,这有两个元组,a1有A值。这些元组有同样名c1的C值。同样的,具有A值的两个元组有相同的C值,没有其他两个不同的元组有相同的A值。C属于A,然而A不满足。考虑t1和t2这两个元组有同样的C值,但他们各自的A值不同。因此,在一对元组t1,t2有t1[C]=t2[C],但t1[A]不等于t2[A]。
部分函数依赖是不足以提的因为他满足所有关系。例如,A A满足于所有涉及的关于A的关系。从字面上读函数依赖的定义,我们看到,对于所有的元组t1和t2,例如有t1[A]=t2[A],是t1[A]=t2[A]的关系。同样的对于AB A满足所有涉及A的关系。一般来说,如果B包含与A那么函数A对B的函数所属依赖性就很小。、
重要的是要认识到一个关系实例可能满足一些函数所属不需要持有关系的体系。在图8.5的课堂关系实例中,我们看到房间号对容纳量是满足的。然而,我们相信,在现实世界中,在不同的建筑中的两个容量不同的教室编号可以是相同的。因此,这是有可能的,在一些时候,在教室的关系中,房间号与容纳量之间是不满足的。所以,我们在设定教室的函数依赖关系集中不能包含房间号对容纳量的依赖。然而,我们可以设立建筑,房间号对于容纳量的依赖在教室图表中。
给定一个函数依赖F保持关系R,它可以在关系集中一定有其他的函数依赖。例如,给定一个模式r(A、B、C)如果在r中有函数依赖A对B,B对C,我们可以推断在关系r中有函数依赖A对C。这是因为,给定任意一个A值只能对应一个C值,对于B值也是同样的,只能对应唯一一个C值。我们将在后面8.4.1中学到,如何做出这种推断。
我们将用符号F+表示F集的结束,也就是可以推断出在F集所有的函数依赖,F+包含了所有F中的函数依赖。
8.3.2 BCNF
BCNF是我们可以获得的更理想的范式之一。它消除了所有基于可发现的多余,正如我们在8.6章中看到的,可能有剩余的其他类型的多余。在BCNF中的一个关系模式R尊重函数依赖F集,对于所有F+中的函数关系 A对于B,A属于R并且B属于R,至少有一个拥有:
A对B是一个平凡函数依赖
A是R模式的一个超码
在BCNF中数据库设计是关于每个成员的关系模式的集合
我们已经在章节8.1中看到不属于BCNF的例子:
研究部中预算依赖于部门名称,但是部门名称不是超键。在章节8.1.2中,我们可以看到将所属部门化为教练和部门是个更好的设计。教练模式在BCNF中。所有非平凡的函数依赖都有,例如:
包括在箭头左边的ID,对于教练ID是一个超键(事实上,是在这种情况下的主键)。(换句话说,没有没有平凡函数依赖的功能在名字,部门名字和工资中没有ID在一边)因此,教练属于BCNF。
相似地,部门属于BCNF因为所有的非平凡函数依赖,例如:
包括箭头的部门名称,并且对于部门部门名称是超键(和主键)因此部门属于BCNF。
我们现在分解的不是一种在BCNF中的一种模式。让R模式不属于BCDN。接着这里至少存在一种平凡函数依赖对于A对BA不是R中的超码。我们用两种模式代替R:
在上面的情况下,A=部门名称,B={建筑,预算}并且部门职能用 来代替。
在这个例子中,证明出B-A=B。我们需要制定规则来正确处理出现在箭头两侧的属性的依赖性。之一技术原因将会在后面的章节8.5.1中揭开。
当我们分解一个不属于BCNF的模式,它可能有一个或以上不是BCNF的原因。在这种情况下,需要进一步分解,最终的结果是一组BCNF。
8.3.3 BCNE和依赖保护
我们已经看到许多表达数据库一致性的约束方法:超键,函数依赖,检查约束,触发器和断言。每次更新时测试这些数据库约束都是很贵的,因此,对数据库进行有效的测试是非常有用的。尤其是如果测试一种函数依赖可以通过只考虑一个关系来完成,那么测试这个约束的成本就很低。我们可以看到,在某些情况下分解成BCNF可以防止某些函数依赖。
为了解释这些,假设我们在大学组织的一个小变化。在图7.15,一个学生可能只有一个建议者。在这个建议者的关系集中学生和建议者是多对一的关系。这小的改变中让给一个顾问只能与一个单一的部门和一个学生可能有超过一个的建议者,但最多只来自一个所给的部门。
通过E-R图的设计一个三元关系代替建议者关系集这一种方法来实施这个变化,涉及整体集顾问,学生和部门这是多对一的关系{学生,顾问}对于部门在表8.6中所示。E-R图中指定约束,“一个学生可以有一个以上的顾问,但最多只有一个对应的给定部门”。
有了这个新的E-R图,图中的顾问,部门和学生不变。然而,现在的模式来自部门建议者:
虽然E-R图中没有指定,假设我们有额外的约束“一个教练可以作为一个部门的顾问”。
接着,下面的函数依赖性放在部门顾问上:
第一个依赖功能源于我们的要求:“一个顾问只担任一个部门的建议者。”第二个功能依赖的是我们的要求。“一个学生可能有做多一个建议者贼所给的一个部门中”。
注意在这种设计中,我们不得不重复部门名称一次当一个顾问加入部门建议者关系时。我们看到部门建议者不属于BCNF因为i_ID不是一个超键。顺从我们BCNF的分解规则,我们得到: (s ID , i ID ) (i ID , dept name)
上述两种模式都是BCNF。(事实上,通过BCNF的定义你可以验证任何模式只有两个属性)。然而,在我们BCNF的设计中,没有包括所有属性出现在函数依赖的模式。
因为我们的设计让强行执行这个功能很难依赖在计算上,因此我们说我们的设计是不依赖保存的。由于依赖保存通常被认为是可取的,我们考虑到另一种比BCNF弱的正常形式,它会允许我们保存依赖的这种关系。这种范式被称为第三范式。
8.3.4
BCNF要求所有非平凡依赖项的形式为α→β,α是超级键。第三种范式(3NF)允许某些非平凡的函数依赖,而非超级键稍微放松了这个约束。在定义3NF之前,我们记得候选密钥是超级键,也就是说,一个超级键,它的适当子集也是超级键。
关系模式R是第三范式,关于函数依赖的集合F,对于F表格中的所有函数依赖项α→β,其中α、β都属于R,至少有以下一种情况。
α→β是一个简单的函数依赖项。
α是R的超级密钥。
Β-α中的每个属性A都包含在候选密钥中。
注意上面的第三个条件并不表示单个候选码必须包含 B一a 中的所有属性。B一a 中的每个属性 A 都可以包含在不同的候选键中。
前两种选择与 BCNF 定义中的两种替代方案相同。3NF 定义的第三个备选方案似乎相当不直观, 而且不清楚为什么它是有用的。在某种意义上, 它代表了 B 的最小松弛 (NF 条件, 这有助于确保每个架构都具有依赖项保留分解为3NF。当我们研究分解为3NF 时, 它的目的将变得更加清晰。
注意任何满足 BCNF 的模式也满足 3 nf, 因为它的每个功能依赖项都将满足前两种选择之一。BCNF 因此是一个限制性更强的正常形式比3NF。
3NF 的定义允许某些功能依赖项不
允许在 BCNF。在 BCNF 中不允许仅满足3NF 定义的第三种选择的依赖项, 但允许在3NF 中一条。
现在, 让我们再次考虑 dept_advisor 关系集, 它具有以下功能依赖性:
i_ID 一dept_name
i_ID 一dept_name一i_name
从技术上讲, 其属性不全部显示在任何一个架构中的依赖关系仍然是隐式强制执行的, 因为存在其他依赖项, 这意味着逻辑上我们在后面的8.4.5 节中处理该情况。你可能已经注意到, 我们跳过第二个正常的表格, 只在历史意义上, 并没有在实践中使用。这些依赖项是可传递依赖项的示例 (参见练习练习 8.16)。3NF 的原始定义是在传递依赖性方面。我们使用的定义是等价的, 但更容易理解。
在8.3.3 节中, 我们争辩说, 功能依赖性 "i_ID 一dept_name" 导致 dept_advisor 架构不在 BCNF 中。注意这里α = i_ID, b = dept_name, 和 b a = dept_name。由于功能依赖项 s_ID, dept_name 一i_ID 在 dept_advisor 上保留, 因此属性部门名称包含在候选键中, 因此 dept_advisor 位于3NF。
我们已经看到的权衡, 必须在 BCNF 和3NF 之间, 当没有依赖关系保存 BCNF 设计。8.5.4 节更详细地介绍了这些权衡。
8.3.5 更高的范式
使用功能依赖项分解架构可能不足以避免某些情况下不必要地重复信息。考虑一下讲师实体集定义中的细微变化, 我们会在其中记录一组儿童姓名和一组电话号码。电话号码可以由多个人共享。因此, 电话号码 和 child_name 将是多值属性, 按照我们从电子 R 设计中生成架构的规则, 我们将有两个架构, 一个用于每一个多值属性、电话号码 和 child_name:
(ID,child_name)
(ID,phone_name)
如果我们要结合这些模式来获得
(ID,child_name,phone_name)
我们会发现结果是在 BCNF, 因为只有非平凡的功能依赖性持有。因此, 我们可能会认为这样的组合是一个好主意。然而, 这样的组合是一个坏主意, 我们可以看到, 通过考虑一个教师与两个孩子和两个电话号码的例子。
例如, 让 ID 为99999的讲师有两个名为 "David" 和 "威廉" 的孩子, 两个电话 numbers,5125551234 和 5125554321.在组合架构中, 我们必须为每个从属关系重复一次电话号码:
如果我们没有重复电话号码, 只存储第一个和最后一个元组, 我们将记录从属名称和电话号码, 但是得到的元组将意味着大卫相当于51 2-555-1234,而威廉相当于我们知道512-555-4321.就如我们所知道的一样,这是不正确的。
因为基于函数依赖正常形态不足以应付这样的情况下,其他的依赖关系和正常的形式已经确定。我们在第8.6和8.7覆盖这些。