四巨头第四周作业翻译

8.3  使用函数依赖进行分解

在 Section8.1 中, 我们提到有一个正式的方法来评估关系架构是否应该被分解。此方法基于键的概念和函数依赖。在讨论关系数据库设计的算法时, 我们将需要讨论任意的关系及其构架, 而不只是谈例子。回顾我们在2章中对关系模型的介绍, 我们在这里总结了我们的表示法。

通常, 我们使用希腊字母作为属性集 (例如α)。我们使用小写罗马字母后跟一个大写的罗马字母在括号里指代关系架构 (例如 r (R))。我们使用符号 r (R) 来显示架构是用于关系 r, R 表示属性集, 但有时我们会简化我们的表示法, 以便在关系名称对我们无关紧要时使用R。

当然, 关系架构是一组属性, 但并非所有属性集都是架构。当我们使用小写的希腊字母时, 我们指的是一组可能是架构或者不是架构的属性。我们希望在指出一组属性完全是架构的时候使用一个罗马数字。

l       当一组属性是超键时, 我们用大写的K表示它.。超键属于特殊关系模式, 所以我们使用术语 "K 是r(R)的超键。

l       我们使用小写字母为关系命名。在我们的示例中, 这些名称要是真实的 (例如, 讲师), 而在我们的定义和算法中, 我们使用单个的字母, 比如r。

l       当然,一个关系, 在给定的任何时间内有一个特殊的值; 我们将其称为实例, 并使用 "r 实例" 一词来表示它。当我们正在讨论一个实例时, 我们可以使用隐含的关系名称 (例如 r)。

8.3.1 键和函数依赖

数据库会在现实世界中建模一组实体和关系。现实世界中的数据通常有各种各样的约束 (规则)。例如, 在大学数据库中预期会存在一些约束:

  1. 学生和教师的身份是独一无二的。
  2. 每个学生和老师只有一个名字。
  3. 每个教师和学生(主要)只与一个部门联系在一起。
  4. 每个部门的预算只有一个值,而且只有一个相关的架构。

 

满足所有这些现实约束的关系的实例称为关系的合法实例;数据库的合法实例中所有关系实例都是是合法的实例。

一些最常用的类型的现实世界的约束可以表示正式作为键(超键、候选键和主键),或作为函数依赖,我们下面来定义。

在第2.3节中,我们定义了超键的概念,它是一个或多个属性的集合,这些属性集合在一起,使我们能够在关系中唯一地识别一个元组。我们重申这个定义如下:让r(R)成为一个关系模式。在r(R)的任何合法实例中,R的子集K是r(R)的超键,在r的实例中,对于所有对t1和t2的元组,如果t1 ≠ t2,那么t1[K] ≠ t2[K]。也就是说,在任何关系r(R)的任何合法实例中,没有两个元组在属性集合K上具有相同的值。显然,如果r中的两个元组在K上有相同的值,那么K值就会识别出唯一一个元组。

而超键是一组唯一标识整个元组的属性,而函数依赖则允许我们表达约束,以唯一地标识某些属性的值。考虑一个关系模式r(R),并让α⊆R和β⊆R.。

l       鉴于r(R)的一个实例,我们说如果实例中的所有成对的元组t1和t2满足函数依赖α→β,t1(α)= t2(α),它也是,t1(β)= t2(β)。

l       我们说,如果在r(R)的每个合法实例中都满足函数依赖,那么它的函数依赖关系就会保持在模式r(R)中。

使用函数依赖符号,我们说如果函数依赖关系K →R保持在r(R)上,那么K是r(R)的超键。换句话说,如果r(R)的每个合法实例,对于每一对元组 t1和t2都是一个超键,当t1[K] = t2[K]时,也就是t1[R] = t2[R](也就是t1 = t2)。

函数依赖关系允许我们表达我们无法用超键表示的约束。在第8.1.2节中,我们考虑到了模式:

Inst_dept (ID, name, salary, dept name, building, budget)

在其中,函数依赖项的名称和预算保持不变,因为每个部门(由部门名称标识)都有一个惟一的预算金额。我们表示这两个属性(ID, 部门名称)通过写入来形成inst_dept的超键:

ID, dept_name→name, salary, building, budget

我们将以两种方式使用函数依赖性:

1、测试关系的实例,看看它们是否满足给定的函数依赖项F。

2、明确合法关系的约束。因此,我们只关心那些满足给定的函数依赖集的关系实例。如果我们想要约束我们自己在满足一个集合F(函数依赖)的模式r(R)上的关系,我们就说F在r(R)上成立。

让我们考虑图8.4的关系r实例,看看哪些函数依赖项得到了满足。注意:A C是被满足的。有两个元组,它们的值是a1。这些元组具有相同的C值,即c1。类似地,两个具有A值的元组具有相同的C值,c2。没有其他成对的不同元组具有相同的值。然而,函数依赖关系C . A并不满足。要知道它不是,考虑元组t1 =(a2,b3,c2,d3)和t2 =(a3,b3,c2,d4)。这两个元组有相同的C值,c2,但是它们有不同的值,分别是a2和a3。因此,我们发现了一对元组t1和t2,这样t1[C] = t2[C],但是t1[a] = t2[a]。

一些函数依赖项被认为是微不足道的,因为它们是由所有的关系所满足的。例如,A对所有涉及属性A的关系都满足。从字面上理解函数依赖的定义,即对于所有的元组t1和t2,这样t1[A] = t2[A],就是t1[A] = t2[A]。同样的,在所有涉及属性a的关系中,AB都能得到满足。一般来说,表格里的函数依赖是微不足道的。重要的是要认识到,关系的一个实例可能满足某些函数依赖关系,而这些依赖关系并不需要保持关系的模式。在图8.5的课堂关系中,我们看到房间号的容量是满足的。但是,我们相信,在现实世界中,不同建筑的两个教室可以有相同的房间号,但房间容量不同。因此,有可能在一段时间内,有一种教室关系的实例,其中房间号的容量是不满足的。因此,我们不会将房间号的容量包含在与教室关系模式相关的函数依赖项集合中。所以,我们会从房间号的容纳能力在课堂模式上来构想函数依赖的构建。

给定一组函数依赖f保持关系r(r),它可以可以推断,某些其他函数依赖也必须保持关系。例如,给定一个模式R(a,b,c),如果函数依赖一个→B和B→C,我们可以推断函数依赖一个→C也必须持有R。这是因为,给定任何值A只能是一个对应的B值,对应B的值只能有一个。我们的研究后,在第8.4.1内,如何做出这样的推论。

我们将用符号F表示集合F的闭合,也就是集合。在给定F的基础上,可以推断出所有的函数依赖性。包含F.中所有的函数依赖项。

8.3.2博伊斯–Codd范式

我们可以获得更理想的正常形式之一是博伊斯–Codd范式(BCNF)。它消除了所有基于可发现的冗余。但是,在函数依赖项中,正如我们在第8.6节中所看到的,可能有剩余的其他类型的冗余。一个关系模式R是BCNF的遵循对于函数依赖关系的集合f,如果形式α→β,哪里α⊆R和β⊆R,拥有以下至少一个:

•α→β是平凡的函数依赖(即β⊆α)。

•α对于图示R是一种超键。

数据库设计是BCNF每个成员的关系模式的集合,构成设计在BCNF。

我们已经在第8.1节中看到了一个关系模式的例子,它不在BCNF:

研究所部(ID、姓名、薪金、部门名称、建筑物、预算)

函数依赖项dept名称在inst dept上保留,但是部门名称。不是一个超键(因为,一个部门可能有许多不同的讲师)。在第8.1.2节中,我们看到了研究所系对讲师的分解。而部门是一个更好的设计。教师模式在BCNF中,所有的不重要的函数依赖项,例如:

ID→名称、部门名称、工资

在箭头的左侧包含ID, ID是一个超键(实际上,在本例中,主键)给教练。(换句话说,没有非平凡的函数依赖于任何名称、部门名称和薪水的组合,没有ID一面。)因此,讲师在BCNF。类似地,部门模式也在BCNF中,因为所有非琐碎的函数依赖项都保持不变,例如:

部门名称→建设、预算

在箭头的左侧包含部门名称,部门名称是一个超键和部门的主键。因此,部门在BCNF。

我们现在提出了一种不存在于BCNF中分解的一般规则。让R是一个不在BCNF的模式。然后至少有一个非平凡的函数。依赖→这样不是超键代替r(R) .我们在我们的设计两个模式:

l       (α∪β)

l       (R--(α-β))

在本月部门中,α=部门名称,{β=(建筑,预算)},本月部门被取代:

l       (α∪β)={部门名称,建筑,预算}

l       (R--(α-β))={姓名,部门名称,薪水}

在这个例子中,结果是β-α=β。我们需要把规则说出来。是否正确处理具有属性的函数依赖项?出现在箭头的两边。稍后将介绍这方面的技术原因。8.5.1节。

当我们分解一个不在BCNF中的模式时,它可能是一个或多个。产生的模式不在BCNF中。在这种情况下,进一步分解。必要的,最终的结果是一组BCNF模式。

8.3.3 BCNF和依赖性保存

我们已经看到了几种表达数据库一致性约束的方法:主键约束、函数依赖、检查约束、断言、和触发器。每次更新数据库时都要测试这些约束。因此,以约束的方式设计数据库是非常有用的。可以有效地进行测试。特别是,如果测试一个函数依赖项可以是。通过只考虑一个关系,测试这个约束的成本很低。我们将看到,在某些情况下,分解为BCNF可以防止效率。测试某些函数依赖项。

为了说明这一点,假设我们对我们的大学做了一个小小的改变。组织。在图7.15的设计中,一个学生可能只有一个顾问。这是来自于关系集顾问从学生到。顾问。我们所要做的“小”改变是指导者可以与之相关联。只有一个部门和一个学生可能有不止一个顾问,但大多数人都来自某个部门。

使用E-R设计实现此更改的一种方法是替换。顾问关系集与三元关系集,部门的顾问有涉及。实体设置讲师、学生和部门,从学生、讲师到部门的多对一,如图8.6所示。E-R图指定,对应于一个给定的部门“一个学生可能有不止一个顾问,但最多一个。”。

有了这个新的E-R图,教师,部门,和学生都不变。但是,部门顾问派生的模式现在是:

部门顾问(s -ID, i- ID, dept _name)

虽然没有在E-R图中指定,假设我们有额外的约束:“教师只能担任一个部门的顾问。”

然后,下面的函数依赖关系控制了部门顾问:

I- ID → dept name

s -ID, dept_ name → i -ID

第一个函数依赖是根据我们的要求“一个讲师”只能担任一个部门的顾问。“第二个函数相关根据我们的要求,鉴于部门,“一个学生最多只能有一个顾问。” 。

注意,在这个设计中,我们被迫重复部门名称。每一次,教师都要参与一项dept顾问关系。我们看到那个部门顾问不在BCNF,因为i -ID不是一个超键。在我们的规则中对于BCNF分解,我们得到:

(s -ID, i- ID)

(i- ID, dept _name)

上述模式都是BCNF。(实际上,您可以验证任何模式。根据定义,BCNF中只有两个属性。但是请注意,在我们的BCNF设计中,没有包含函数中出现的所有属性的模式。依赖s -ID,部门名称→i-ID

因为我们的设计使计算很难执行这个函数依赖,我们说我们的设计不是依赖保护。因为依赖性保存通常被认为是可取的,我们认为另一种正常形式,比BCNF更弱,这将允许我们保持依赖关系。这种正常形式称为第三范式。

8.3.4  第三范式

BCNF要求所有非琐细的依赖都是形式的,其中是一个超键。第三范式(3NF)通过允许某些非平凡的函数依赖(其左侧不是超键)稍微放松了这个约束。在定义3NF之前,我们还记得一个候选键是一个最小的超键——也就是说,一个超键没有属性,它也是一个超键。

一个关系模式R在函数依赖关系的集合F中处于第三个正常的形式,如果在F+的形式的所有函数依赖关系中α→β, α ⊆ R,β ⊆ R,至少有一个是这样的:

•是一种微不足道的函数依赖。

•是R的超键。

•每个属性A都包含在R的候选键中。

注意,上面第三个条件没有说一个候选键−必须包含的所有属性;每个属性A可以包含在不同的候选关键字中。

前两种选择与BCNF定义中的两种替代方法相同。3NF定义的第三种选择似乎很不直观,它为什么有用并不明显。从某种意义上说,它代表了BCNF条件的最小要求,这有助于确保每个模式都有一个被依赖的分解为3NF。当我们研究时分解为3NF,就会变得更加清楚。

注意,任何满足BCNF的模式也满足3NF,因为它的每个函数依赖都满足前两种选择之一。因此,BCNF比3NF更受限制。

3NF的定义允许在BCNF中没有部分依赖。α 依赖 β只满足第三范式不满足BCNF,在3NF是允许的

现在,让我们再次考虑dept_advisor关系集,它具有以下函数依赖项:

i_ID→dept_name

s_ID, dept_name→i ID

在第8.3.3节中,我们讨论了函数依赖关系“i_ID dep_name”导致了dept_advisor模式不在BCNF中。注意这里α=i_ID、B=dept¬_name,β-α=dept_name,s_ID在dept_advisor中保存,属性dept_name包含在一个候选关键字中,因此dept_advisor在3NF中。

我们已经看到BCNF和3NF之间必须进行的权衡,因为没有任何依赖的BCNF设计。这些在第8.5.4节中有更详细的描述

8.3.5高等范式

使用函数依赖来分解模式可能不足以避免某些情况下不必要的信息重复。请考虑一下教师的“实体集”定义中的一个细微的变化,在这个定义中,我们记录每个教师一组孩子的名字和一组电话号码。电话号码可以由多人共享。因此,电话号码和孩子的名字将是多值依赖,按照我们的规则,从E-R设计中生成模式,我们将有两个模式,一个用于每个多值依赖,电话号码和孩子的名字:

(ID, 孩子的名字)

(ID, 电话号码)

如果我们要结合这些模式。

(ID, 孩子的名字, 电话号码)

我们会发现结果是在BCNF中,因为只有非平凡的函数依赖保持不变。因此,我们可能认为这样的组合挺好。然而,这样的组合是并不合适,因为我们可以通过考虑一个有两个孩子和两个电话号码的老师的例子来看到。例如,让ID 99999的老师有两个孩子,名字叫“David”和“William”,还有两个电话号码,512-555-1234和512-555-4321。在这种模式中,我们必须对每个依赖值重复一次电话号码:

(99999, David, 512-555-1234)

(99999, David, 512-555-4321)

(99999, William, 512-555-1234)

(99999, William, 512-555-4321)

如果我们不重复电话号码,并且只存储第一个和最后一个元组,我们就会记录下依赖的名称和电话号码,但是结果的元组意味着David对应的是512-555-1234,而William对应的是512-555-4321。这是不正确的。

因为基于函数依赖关系的正常不足够处理这样的情况,所以已经定义了其他依赖关系和范式。我们将在第8.6和8.7节中讨论这些问题。

posted @ 2018-04-01 22:56  一个烤羊腰子  阅读(150)  评论(0编辑  收藏  举报