关系数据库设计

关系数据库设计的目标是生成一组关系模式,使我们存储信息时避免不必要的冗余,并且可以方便地获取信息。并通过满足适当范式(normal form)来实现设计的优化。

好的关系设计的特点

好的设计会尽可能少的引入冗余数据,或做有损拆分,而是使用规范的方法找到正确的分解。

原子域和第一范式

在关系模型中,将属性不具有任何子结构这种思想形式化。一个域是原子的(atomic),如果该域的元素被认为是不可分的单元。我们称一个关系模式R属于第一范式(First Normal Form,1NF),如果R的所有属性的域都是原子的。简单来说,当关系模式满足第一范式时,该关系模式所有属性的域都是原子的。常见的非原子域实例如下:

  • (1) 名字的集合是一个非原子值的实例。如使用属性children记录孩子的名称。如果有多个children,那么属性children将是一个名字的集合。
  • (2) 组合属性具有非原子域。如包含子属性street、city、state和zip的属性address。
  • (3) 使用以集合为值的属性会导致冗余存储数据的设计,进而会进一步导致不一致。如数据库设计者可能不将教师和课程安排之间的联系表示为一个单独的关系teaches,而是尝试为每一个教师存储一个课程段标志号的集合,并为每一个课程段存储一个教师标志号的集合。每当关于哪位教师讲授哪个课程段的数据发生变化时,就需同时更新两个地方:课程段的教师集合和教师的课程段集合。对这两个更新的执行失败,会导致数据库处于不一致的状态。如果只保留一个,将避免信息的重复。但是,只保留一个会导致某些查询变得复杂,并且也不好确定保留哪一个。(在设计数据库时,要注意这种误区)
  • (4) 有时,非原子值也有其价值。在许多含有复杂结构的实体域中,强制使用第一范式会给应用程序带来不必要的负担,如必须编写代码把数据转换成原子形式。从原子形式来回转换数据也会有运行时额外开销。所以,这种场景支持非原子的值很有用。事实上,现代数据库的确支持很多类型的非原子值。如支持创建复合属性、集合、数组等复杂数据类型。

使用函数依赖进行分解

存在一个规范方法判断一个关系模式是否应该分解。这个方法基于码和函数依赖的概念。

码和函数依赖

一个数据库对现实世界中的一组实体和联系建模。在现实世界中,数据上通常存在各种约束(规则)。如,在一个大学数据库中预计要保证的一些约束有:

  • (1) 学生和教师通过ID唯一标识。
  • (2) 一个老师可以负责多门课程。
  • (3) 一个学生可以选择多门课程。

一个关系的满足所有这种现实世界约束的实例,称为关系的合法实例(legal instance)。
几种最常见的现实世界约束可以形式化地表示为码(超码、候选码以及主码),或者下面所定义的函数依赖(可以使用码或函数依赖描述现实世界的约束):
超码是可以唯一标识关系中一条元组的一个或多个属性的集合。超码的数学定义如下:
令r(R)是一个关系模式。R(属性集)的子集K是r(R)的超码,当且仅当:在关系r(R)的任意合法实例中,r的实例中的所有元组对 t 1 t_1 t1 t 2 t_2 t2总满足,如 t 1 t_1 t1 t 2 t_2 t2,则 t 1 t_1 t1[K]≠ t 2 t_2 t2[K]。也就是说,在关系r(R)的任意合法实例中没有两条元组在属性集K上可能具有相同的值。也即在r中一个K值唯一标识一条元组。
考虑一个关系模式r(R),令α ⊆ \subseteq R且β ⊆ \subseteq R:

  • 给定r(R)的一个实例,这个实例满足(satisfy)函数依赖α → \rightarrow β的条件是:对实例中所有元组对 t 1 t_1 t1 t 2 t_2 t2,若 t 1 t_1 t1[α]≠ t 2 t_2 t2[α],则 t 1 t_1 t1[β]≠ t 2 t_2 t2[β]。
  • 如果在r(R)的每个合法实例中都满足函数依赖α → \rightarrow β,则说函数依赖在模式r(R)上成立(hold)。
    使用函数依赖表述超码如下:如果函数依赖K → \rightarrow R在r(R)上成立,则K是r(R)的一个超码。

可以使用如下两种方式使用函数依赖:

  • 判定关系的实例是否满足给定函数依赖集F。
  • 说明合法关系集上的约束。如果我们希望只考虑模式R上满足函数依赖集F的关系,那么F在r(R)上成立。

平凡的函数依赖:如果β ⊆ \subseteq α,则形如α → \rightarrow β的函数依赖是平凡的。平凡的函数依赖在所有关系中都满足。如AB ⊆ \subseteq A,则对所有满足 t 1 t_1 t1[AB]= t 2 t_2 t2[AB]的元组 t 1 t_1 t1 t 2 t_2 t2,有 t 1 t_1 t1[A]= t 2 t_2 t2[A]。注意,AB → \rightarrow A在所有包含属性A的关系中均满足。
我们使用符号 F + F^+ F+来表示F集合的闭包(closure),也就是能够从给定F集合推导出的所有函数依赖的集合。显然, F + F^+ F+包含F中所有的函数依赖。

Boyce-Codd范式(BCNF, 巴斯范式)

Boyce-Codd范式(Boyce-Codd Normal Form,BCNF,巴斯范式)消除所有基于函数依赖能够发现的冗余。具有函数依赖集F的关系模式R属于BCNF的条件是,对 F + F^+ F+中所有形如α → \rightarrow β的函数依赖(α ⊆ \subseteq R且β ⊆ \subseteq R),下面至少有一项是成立:

  • α → \rightarrow β是平凡的函数依赖(即β ⊆ \subseteq α)。
  • α是模式R的一个超码。

一个数据库设计属于BCNF的条件是,构成该设计的关系模式集中的每个模式都属于BCNF。
对于不属于BCNF的模式需要进一步分解。设R为不属于BCNF的一个模式。则存在至少一个非平凡的函数依赖α → \rightarrow β,其中α不是R的超码。那么在设计中可以使用以下两个模式取代R:

  • ⋃ \bigcup β)
  • (R - (β - α))

当分解不属于BCNF的模式时,产生的模式可能有一个或多个不属于BCNF。在这种情况下,需要进一步分解,其最终结果是一个BCNF模式集合。更多分解实现参考分解算法

BCNF和保持依赖

一致性约束,如主码约束、函数依赖、check约束、断言和触发器,会带来数据库更新时,检查约束的开销。因此,将数据库设计成能高效地检查约束是很有用的。特别地,如果函数依赖的检测仅需考虑一个关系就可完成,那么检查这种约束的开销就很低。有些情况下,到BCNF的分解会妨碍对某些函数依赖的高效检查。
使用BCNF会使保持函数依赖变得困难,因此我们考虑另外一种比BCNF弱的范式,它允许我们保持依赖。该范式称为第三范式。

第三范式

第三范式是比BCNF弱的范式。任何满足BCNF的模式也满足3NF。具有函数依赖集F的关系模式R属于第三范式(third normal form)的条件是:对 F + F^+ F+中所有形如α → \rightarrow β的函数依赖(α ⊆ \subseteq R且β ⊆ \subseteq R),下面至少有一项是成立:

  • α → \rightarrow β是平凡的函数依赖(即β ⊆ \subseteq α)。
  • α是模式R的一个超码。
  • β - α中的每一个属性A都包含于R的一个候选码中。

前两个条件与BCNF定义中的两个条件相同。第三个条件,在某种意义上,代表BCNF条件的最小放宽,以确保每一个模式都有保持依赖的3NF分解。
在某些情况下,使用函数依赖分解模式可能不足以避免不必要的信息重复。(有些情况,使用基于函数依赖的范式,无法避免信息重复,需要定义另外的依赖和范式)

函数依赖理论

函数依赖集的闭包

当检验范式时,只考虑给定的函数依赖集是不够的,还需考虑模式上成立的所有函数依赖
给定关系模式r(R),如果r(R)的每一个满足函数依赖集F的实例也满足 f f f,则R上的函数依赖 f f f被r上的函数依赖集F逻辑蕴涵(logically imply)。假设给定关系模式r(A,B,C)及函数依赖集:A → \rightarrow B、B → \rightarrow C,那么函数依赖B → \rightarrow C被逻辑蕴涵。
令F为一个函数依赖集,F的闭包是被F逻辑蕴涵的所有函数依赖的集合,记作 F + F^+ F+
Armstrong公理(Arstrong’s axiom)提供一种用于推理函数依赖的更为简单的技术。在下面的公理(也称规则)描述中,用希腊字母(α,β,γ,…)表示属性集,用字母表中大写罗马字母表示单个属性。用αβ表示α ⋃ \bigcup β。Armstrong公理包含如下三条规律:

  • (1) 自反律(reflexivity rule)。若α为一属性集且β ⊆ \subseteq α,则α → \rightarrow β成立。
  • (2) 增补律(augmentation rule)。若α → \rightarrow β成立且γ为一属性集,则αγ → \rightarrow βγ。
  • (3) 传递律(transitivity rule)。若α → \rightarrow β和β → \rightarrow γ成立,则α → \rightarrow γ成立。

Armstrong公理是正确有效的(sound),因为它们不产生任何错误的函数依赖。同时,Armstrong公理是完备的(complete),因为对于给定函数依赖集F,它们能产生全部 F + F^+ F+。可以通过反复使用Armstrong公理,找出给定F的全部 F + F^+ F+
虽然Armstrong公理是完备的,但直接使用它们计算 F + F^+ F+会很麻烦。为进一步简化,列出另外一些规则:

  • (1) 合并律(union rule)。若α → \rightarrow β和α → \rightarrow γ成立,则α → \rightarrow βγ成立。
  • (2) 分解律(decomposition rule)。若α → \rightarrow βγ成立,则α → \rightarrow β和α → \rightarrow γ成立。
  • (3) 伪传递律(pseudotransitivity rule)。若α → \rightarrow β和βγ → \rightarrow δ成立,则αγ → \rightarrow δ成立。

使用Armstrong公理计算 F + F^+ F+的过程如下:
F + F^+ F+ := F
 repeat
  for each F + F^+ F+中的函数依赖 f f f
   在f上应用自反律和增补律
   将结果加入到 F + F^+ F+
  for each F + F^+ F+中的一对函数依赖 f 1 f_1 f1 f 2 f_2 f2
   if f 1 f_1 f1 f 2 f_2 f2 可以使用传递律结合起来
    将结果加入到 F + F^+ F+
 until F + F^+ F+不再发生变化
函数依赖的左边和右边都是R的子集。由于包含n个元素的集合有 2 n 2^n 2n个子集,因此共有 2 n 2^n 2n✖️ 2 n 2^n 2n= 2 2 n 2^{2n} 22n个可能的函数依赖,其中n是R中的属性个数。

属性集的闭包

如果α → \rightarrow B,其中α表示属性集、B表示属性,我们称属性B被属性集α函数确定(functionally determine)。
令α为一个属性集,将函数依赖集F下被α函数确定的所有属性的集合称为F下α的闭包,记为 α + α^+ α+。计算 α + α^+ α+的算法如下:
result := α
 repeat
  for each F中函数依赖β → \rightarrow r
   if β ⊆ \subseteq result
    result := result ⋃ \bigcup γ
 until result不变
属性闭包算法有多种用途:

  • 为了判断α是否为超码,可以计算 α + α^+ α+,检查 α + α^+ α+是否包含R中的所有属性。
  • 通过检查是否β ⊆ \subseteq α + α^+ α+,可以检查函数依赖α → \rightarrow β是否成立(也就是,是否属于 F + F^+ F+)。(这种检查十分有用)
  • 给出另一种计算 F + F^+ F+的方法:对任意的γ ⊆ \subseteq R,找出闭包 γ + γ^+ γ+;对任意的S ⊆ \subseteq γ + γ^+ γ+,输出一个函数依赖γ → \rightarrow S。

正则覆盖

假设在一个关系模式上有一个函数依赖集F。每当用户在该关系上执行更新时,数据库系统必须确保此更新不破坏任何函数依赖。如果更新操作破坏了F上的任一个函数依赖,系统必须回滚该更新操作。
我们可以通过测试与给定函数依赖集具有相同闭包的简化集的方式来减小检测冲突的开销。因为简化集和原集具有相同的闭包,所以满足函数依赖简化集的数据库也一定满足原集,反之亦然。(使用简化集替换原集,便于检测数据库的函数依赖
稍后将看到简化集是如何构造的。首先,需要一些定义。
如果去除函数依赖的一个属性不改变该函数依赖集的闭包,则称该属性是无关的(extraneous)。无关属性(extraneous attribute)的形式化定义如下:考虑函数依赖集F及F中的函数依赖α → \rightarrow β。

  • 如果A ∈ \in α并且F逻辑蕴含(F-{α → \rightarrow β}) ⊆ \subseteq {(α-A) → \rightarrow β},则属性A在α中是无关的。
  • 如果A ∈ \in β并且函数依赖集F-{α → \rightarrow β}) ⊆ \subseteq → \rightarrow (β-A)}逻辑蕴含F,则属性A在β中是无关的。

有效检验一个属性是否无关可参考链接。
F的正则覆盖(canonical cover) F c F_c Fc是一个依赖集,使得F逻辑蕴含 F c F_c Fc中的所有依赖,并且 F c F_c Fc逻辑蕴含F中的所有依赖。此外, F c F_c Fc必须具有如下性质:

  • F c F_c Fc中任何函数依赖都不含无关属性。
  • F c F_c Fc中函数依赖的左半部都是唯一的。即, F c F_c Fc中不存在两个依赖 α 1 α_1 α1 → \rightarrow β 1 β_1 β1 α 2 α_2 α2 → \rightarrow β 2 β_2 β2,满足 α 1 α_1 α1= α 2 α_2 α2

注意,当检验一个属性是否无关时,检验时用的是 F c F_c Fc当前值中的函数依赖,而不是F中的函数依赖。如果一个函数依赖的右半部分只包含一个属性,并且这个属性是无关的,那么我们将得到一个右半部分为空的函数依赖。这样的函数依赖应该删除。
计算函数依赖集F的正则覆盖如下:
F c F_c Fc = F
 repeat
  使用合并律将F中所有形如 α 1 α_1 α1 → \rightarrow β 1 β_1 β1 α 1 α_1 α1 → \rightarrow β 2 β_2 β2的依赖替换为 α 1 α_1 α1 → \rightarrow β 1 β_1 β1 β 2 β_2 β2
 在 F c F_c Fc中寻找一个函数依赖α → \rightarrow β,它在α或在β中具有一个无关属性
  // 注意,使用 F c F_c Fc而非F检验无关属性
  如果找到一个无关属性,则将它从 F c F_c Fc中的α → \rightarrow β中删除
 until F c F_c Fc不变
注意,正则覆盖未必是唯一的。

无损分解

令r(R)为一个关系模式,F为r(R)上的函数依赖集。令 R 1 R_1 R1 R 2 R_2 R2为R的分解。如果用两个关系模式 r 1 r_1 r1( R 1 R_1 R1)和 r 2 r_2 r2( R 2 R_2 R2)替代r(R)时没有信息损失,则我们称该分解是无损分解(lossless decomposition)。换句话说,如果我们把r投影至 R 1 R_1 R1 R 2 R_2 R2上,然后计算投影结果的自然连接,仍可得到一模一样的r。不是无损的分解称为有损分解(lossy decomposition)。无损连接分解(lossless-join decomposition)和有损连接分解(lossy-join decomposition)这两个术语有时用来代替无损分解和有损分解。
可以用函数依赖来说明什么情况下分解是无损的。 R 1 R_1 R1 R 2 R_2 R2是R的无损分解,如果以下函数依赖至少有一个属于 F + F^+ F+:

  • R 1 R_1 R1 ⋂ \bigcap R 2 R_2 R2 → \rightarrow R 1 R_1 R1
  • R 1 R_1 R1 ⋂ \bigcap R 2 R_2 R2 → \rightarrow R 2 R_2 R2

换句话说,如果 R 1 R_1 R1 ⋂ \bigcap R 2 R_2 R2 R 1 R_1 R1 R 2 R_2 R2的超码,R上的分解就是无损分解
对于一个模式一次性分解为多个模式的情况,判定无损分解就更复杂了。

保持依赖

可以使用函数依赖理论描述保持依赖。
首先,请注意如果F中的每一个函数依赖都可以在分解得到的某一个关系上验证,那么这个分解就是保持依赖的。但是,这个验证只能作用作一个易于检查的充分条件,如果验证失败,我们也不能断定该分解就不是保持依赖的,而是将不得不采用一般化的验证方法。

分解算法

该部分介绍能生成属于适当范式的设计的算法。

BCNF算法

BCNF的定义可以直接用于检查一个关系是否属于BCNF。但是,计算 F + F^+ F+是一个繁重的任务。下面描述判定一个关系是否属于BCNF的简化检验方法。

BCNF的判定方法

在某些情况下,判定一个关系是否属于BCNF可以作如下简化:

  • 为了检查非平凡的函数依赖α → \rightarrow β是否违反BCNF,计算 α + α^+ α+(α的属性闭包),并且验证它是否包含R中的所有属性,即验证 α + α^+ α+是否是R的超码。
  • 检查关系模式R是否属于BCNF,仅需检查给定集合F中的函数依赖是否违反BCNF,而不用检查 F + F^+ F+中的所有函数依赖。注意,当一个关系分解后,该规则就不适用了。也就是说,当判定R上的一个分解 R i R_i Ri是否违反BCNF时,只用F就不够了。

BCNF分解算法

BCNF分解算法定义如下:
result := {R}
done := false
计算 F + F^+ F+
while not done do
 if result中存在模式 R i R_i Ri不属于BCNF  
  令α → \rightarrow β为一个在 R i R_i Ri上成立的非平凡函数依赖,满足α → \rightarrow R i R_i Ri不属于 F + F^+ F+,并且α → \rightarrow β= ∅ \emptyset
  result := (result- R i R_i Ri) ⋃ \bigcup ( R i R_i Ri-β) ⋃ \bigcup (α,β)
 else
  done := true
用上述算法产生的分解不仅是一个BCNF分解,而且是一个无损分解。
注意,BCNF分解算法所需时间为原始模式规模的指数级别,因为该算法检查分解中的一个关系是否满足BCNF的代价可以达到指数级。

3NF分解

3NF分解算法如下:
F c F_c Fc为F的正则覆盖
i := 0
for each F c F_c Fc中的函数依赖α → \rightarrow β
 i := i + 1
  R i R_i Ri := αβ
if 模式 R j R_j Rj,j=1,2,…,i都不包含R的候选码 then
 i := i + 1
  R i R_i Ri = R的任意候选码
repeat
 if 模式 R j R_j Rj包含于另一个模式 R k R_k Rkthen
  /* 删除 R j R_j Rj */
   R j R_j Rj := R i R_i Ri
  i := i - 1
until 不再有可删除的 R j R_j Rj
return ( R 1 R_1 R1, R 2 R_2 R2,…, R i R_i Ri)  
这个算法也称为3NF合成算法(3NF synthesis algorithm),因为它接受一个依赖集合,每次添加一个模式,而不是对初始的模式反复的分解。该算法的结果不是唯一确定的,因为一个函数依赖集有不止一个正则覆盖,而且,某些情况下该算法的结果依赖于该算法考虑 F c F_c Fc中的依赖的顺序。
有趣的是,3NF分解算法可在多项式时间内实现,尽管判定给定关系是否属于3NF是NP-hard的。

BCNF和3NF比较

对应用函数依赖进行数据库设计的目标是:

  1. BCNF
  2. 无损
  3. 保持依赖

由于不是总能达到所有者三个目标,因为我们也许不得不在BCNF和保持依赖的3NF中做出选择。
BCNF可以消除所有基于函数依赖所能发现的冗余(注意,BCNF不能确保冗余被消除),但无法保证设计是保持依赖的。
3NF的一个优点是可以在满足无损并保持依赖的前提下得到3NF设计。然而,3NF也有一个缺点:可能不得不用空值表示数据项间的某些可能有意义的联系,并且存在信息重复的问题。
值得注意的是,除了可以通过用主码或唯一约束来声明超码的特殊情况外,SQL不提供指定函数依赖的途径。通过写断言来保证函数依赖虽然有点麻烦,但也是有可能的。遗憾的是,目前没有数据库系统支持强制实施函数依赖所需的复杂断言,而且这些断言的开销很大。
虽然在分解不能保持函数依赖时,对函数依赖的检查可能会用到连接,但倘若数据库系统支持物化视图上的主码约束,就可以通过使用物化视图的方式来降低开销。利用一个约束unique(α)或者primary key(α),就可以在物化视图上很容易地检查函数依赖。
从负面来看,物化视图会带来一些时间和空间的额外开销;但从正面来看,应用程序员不需要写代码来保持冗余数据在更新上的一致性。维护物化视图是数据库系统的工作,即在数据库更新时做出相应的更新。遗憾的是,目前绝大多数数据库系统不支持物化视图上的约束。
在不能得到保持依赖的BCNF分解的情况下,通常我们倾向于选择BCNF,因为在SQL中检查非主码约束的函数依赖很困难。

使用多值依赖的分解

有些关系模式虽然属于BCNF,但从某种意义上说仍存在信息重复的问题。如多值属性场景。为处理多值属性问题,需定义一种新的约束形式,称为多值依赖。利用多值依赖定义关系模式的范式称为第四范式(Fourth Normal Form,4NF)。4NF严格于BCNF严格于3NF。

多值依赖

函数依赖规定某些元组不能出现在关系中。如果A → \rightarrow B成立,我们就不能有两个元组在A上的值相同而在B上的值不同。从另一个角度来说,多值依赖并不排除某些元组的存在,而是要求某种形式的其他元组存在于关系中。由于这个原因,函数依赖有时称为相等产生依赖(equality-generating dependency),而多值依赖称为元组产生依赖(tuple-generating dependency)。
令r(R)为一关系模式,并令α ⊆ \subseteq R,且β ⊆ \subseteq R。多值依赖(multivalued dependency)α → \rightarrow → \rightarrow β在R上成立的条件是,在关系r(R)的任意合法实例中,对于r中任意一对满足 t 1 t_1 t1[α]= t 2 t_2 t2[β]的元组对 t 1 t_1 t1 t 2 t_2 t2,r中都存在元组 t 3 t_3 t3 t 4 t_4 t4,使得
t 1 t_1 t1[α] = t 2 t_2 t2[α] = t 3 t_3 t3[α] = t 4 t_4 t4[α]
t 3 t_3 t3[β] = t 1 t_1 t1[β]
t 3 t_3 t3[R-β] = t 2 t_2 t2[R-β]
t 4 t_4 t4[β] = t 2 t_2 t2[β]
t 4 t_4 t4[R-β] = t 1 t_1 t1[R-β]
这个定义看似复杂,实则不然。直观地,多值依赖α → \rightarrow → \rightarrow β是说α和β之间的联系独立于α和R-β之间的联系。若模式R上所有关系都满足多值依赖α → \rightarrow → \rightarrow β,则α → \rightarrow → \rightarrow β是模式R上平凡的多值依赖。
令D表示函数依赖和多值依赖的集合。D的闭包 D + D^+ D+是由D逻辑蕴含的所有函数依赖和多值依赖的集合。与函数依赖相同,可以用函数依赖和多值依赖的规范定义根据D计算出 D + D^+ D+。可以用这样的推理处理非常简单的多值依赖。对于复杂的依赖,用推理规则系统来推导出依赖集。
由多值依赖的定义,可以得出以下规则,对于α,β ⊆ \subseteq R:

  • 若α → \rightarrow β,则α → \rightarrow → \rightarrow β。换句话说,每一个函数依赖也是一个多值依赖。
  • 若α → \rightarrow → \rightarrow β,则α → \rightarrow → \rightarrow R-α-β。

第四范式

函数依赖和多值依赖集为D的关系模式r(R)属于第四范式(4NF)的条件是,对 D + D^+ D+中所有形如α → \rightarrow → \rightarrow β的多值依赖(其中α ⊆ \subseteq R且β ⊆ \subseteq R),至少有以下之一成立:

  • α → \rightarrow → \rightarrow β是一个平凡的多值依赖。
  • α是R的一个超码。
    注意,4NF定义与BCNF定义的唯一不同在于多值依赖的使用。

4NF分解

可以将4NF与BCNF之间的相似之处应用到4NF模式分解中。4NF分解算法如下:
result := {R}
done := false
计算 D + D^+ D+
给定模式 R i R_i Ri,令 D i D_i Di表示 D + D^+ D+ R i R_i Ri上的限定
while not done do
 if result中存在模式 R i R_i Ri不属于4NF  
  令α → \rightarrow → \rightarrow β为一个在 R i R_i Ri上成立的非平凡函数依赖,满足α → \rightarrow R i R_i Ri不属于 D i D_i Di,并且α → \rightarrow β= ∅ \emptyset
  result := (result- R i R_i Ri) ⋃ \bigcup ( R i R_i Ri-β) ⋃ \bigcup (α,β)
 else
  done := true

更多的范式

第四范式不是“最终”的范式。多值依赖有助于理解并消除某些形式的信息重复,而这种信息重复用函数依赖是无法理解的。还有一些类型的约束称作连接依赖(join dependency),它概化了多值依赖,并引出了另一种范式称作投影-连接范式(Project-Join Normal Form, PJNF)(PJNF在某些书中称为第五范式,fifth normal form)。还有一类更一般化的约束,它引出一种称作域-码范式(Domain-Key Normal Form, DKNF)。PJNF和DKNF不仅难以推导,而且没有形成一套具有正确有效性和完备性的推理规则用于约束的推导。因此PJNF和DKNF很少使用。
还有,第二范式(Second Normal Form, 2NF)。因为它只具有历史的意义,所以没有对它讨论。关系模式R属于第二范式,如果R中的每个属性A都满足如下准则之一:

  • (1) 它出现在一个候选码中。
  • (2) 它没有部分依赖于一个候选码。

函数依赖α → \rightarrow β称为部分依赖(partial dependency)的条件是,存在α的真子集γ使得γ → \rightarrow β。我们称β部分依赖于α。

数据库设计过程

引入范式和规范化问题后,本节将研究规范化是如何糅合在整体数据库设计过程中的。
可以采用以下几种方法得到模式r(R):

  1. r(R)可以是由E-R图向关系模式集转换时生成。
  2. r(R)可以是一个包含所有有意义的属性的单个关系。然后规范化过程中将R分解成一些更小的模式。
  3. r(R)可以是关系的即席设计的结果,然后检验它们是否满足一个期望的范式。

E-R模型和规范化

当小心地定义E-R图,并正确地识别所有的实体时,有E-R图生成的关系模式应该不需要太多进一步的规范。然而,一个实体的属性之间有可能存在函数依赖。如假设instructor实体集包含属性dept_name和dept_address,并且存在函数依赖dept_name → \rightarrow dept_address。那么,就要规范化从instructor生成的关系。
如果一个多值依赖成立且不是被相应的函数依赖所隐含的,那么它通常由以下情况引起:

  • 一个多对多的联系集。
  • 实体集的一个多值属性。

对于多对多的联系集,每个相关的实体集都有自己的模式,并且存在一个额外的模式用于表示联系集。对于多值属性,会创建一个单独的模式,包含该属性以及实体集的主码

去规范化

有时候数据库设计者会选择包含冗余信息的模式,也就是说,没有规范化。对一些特定的应用,使用冗余来提高性能。但是,不使用规范化模式的代价是用来保持冗余数据一致性的额外工作。
把一个规范化的模式变成非规范化的过程称为去规范化(denormalization)。设计者用它调整系统的性能以支持响应时间苛刻的操作。

时态数据建模

时态数据(temporal data)是具有关联使得时间段的数据库,在时间段之间数据有效(valid)。使用数据的快照(snapshot)这个术语表示一个特定时间点上该数据的值。
–更多,待补充–

参考

数据库系统概念(第六版) A. Silberschatz H. F. Korth S. Sudarshan著 杨冬青 等译 第八章

你可能感兴趣的:(数据库系统概念)