【数据库】数据库入门(八): 数据库规范化(Normalisation)

前言

数据库规范化的产生主要是由模式设计(Schema Design)而推动的。模式设计的目标是为特定的数据库应用程序选择最合适的模式。模式的选择由用户提供和依赖项捕获的应用程序数据的语义信息指导。
常见的方法是从一个普遍的关系开始,并应用分解来创建满足某些形式的新关系,使用范式进行规范化就是其中之一。

范式的种类(Normalisation Form)

根据约束强弱的差别,范式的种类从弱到强依次是:

(弱约束)1NF → 2NF → 3NF → BCNF → ... (强约束)

其中:

  • 第一范式(1NF):不基于任何的约束,要求每个字段的值都是单一值,用于排除重复元组的出现。
  • 第二范式(2NF):满足第一范式,数据对表的主键与候选键有依赖关系。
  • 第三范式(3NF):满足第二范式,所有非主键属性都只和候选键有相关性,非主键属性之间独立无关。
  • Boyce–Codd 范式(BCNF):满足第三范式,对于任意函数依赖 X → A,都满足 X 是 R 的一个超键。
  • 第四范式(4NF):每个非平凡的多值依赖都有一个超键。
  • 第五范式(5NF):候选键隐含了每个非平凡的连接依赖关系。
  • 第六范式(6NF):每个连接依赖都是平凡的。

下面暂且详细介绍一下 BC 范式和第三范式。

BC范式 (BCNF)

定义

一个数据库 R 满足,对于任意一个非平凡的函数依赖 X → A,X 都是一个超键(superkey)。

根据定义可知,当一个数据模式是 BCNF 时,基于函数依赖的所有数据冗余都会被清除。但是使用 BCNF 设计的数据模式不一定是一个好的设计。该范式的核心在于,不重复在数据库中描述同样的事实(值、函数依赖等)。

BC范式分解算法

输入:关系模式 R',以及 R' 的所有函数依赖的集合 ∑。
输出:满足 BC 范式的所有关系模式的集合 S,且每个关系模式都包含一组函数依赖的集合。
步骤

  • 从 S = { R' } 开始;
  • 迭代对 S 中的每一个关系模式 R 进行一下操作,直至 S 不再变化:
  • 找出 R 中违反 BC 范式的任意一个非平凡函数依赖 X → Y;
  • 在集合 S 中分别用两个关系模式 XY 和 (R - Y)来替代 R。
  • 把 ∑ 中的每个函数依赖映射到最终的关系模式集合 S 中。

当我们对关系模式进行分解时,需要考虑以下两个特点:

  • 无损耗连接(Lossless join):,将自然连接操作应用于分解后的关系时不允许生成假元组的可能性。
  • 依赖保留(Dependency preservation):确保每个功能依赖项都可以从分解后的功能依赖项中推断出来。

根据上面的算法,最后得到的 S 中的每一个关系模式 R,都存在对应的函数依赖,且都满足 BC 范式。但最开始 ∑ 中的函数依赖并不一定会完全保留下来,有部分的函数依赖可能在分解过程中丢失了,但是这些依赖可以通过内连接不同的关系模式得到恢复。因此,BCNF 可以生成一个无损耗的分解,但不一定能生成一个既无损耗又能保留依赖的分解。

第三范式(3NF)

第三范式是一种比 BC 范式宽松一点的约束范式。与 BC 范式相比,第三范式总是可以保证无损耗连接和依赖保留,也就是说,满足第三范式的分解结果不会丢失原来的所有函数依赖。

定义

一个数据库 R 满足,对于任意一个非平凡的函数依赖 X → A,X 都是一个超键(superkey)或者 A 是主要属性(prime attributes)。

由定义可知,满足第三范式的关系模式,可能会保留一些数据冗余,但排除了一些多余的函数依赖,比如:

  • 部分函数依赖(Partial FD):X 是某个键的真子集,一个非主要属性 A 依赖于 X,则称 X → A 是部分函数依赖。
  • 传递函数依赖(Transitive FD):一个非主要属性 A 依赖于 X,但 X 不是任何键的真子集,则称 X → A 是传递函数依赖。

例如,一个关系模式 R = { A,B,C,D},∑ = { A → B,B → C },其中它仅有一个键为 { A,D }。那么

  • A → B 是一个部分函数依赖(A 是键的真子集,B 不是主要属性)。
  • B → C 是一个传递函数依赖(B 不是键的真子集,C 不是主要属性)。

第三范式分解算法

输入:关系模式 R,以及 R 的所有函数依赖的集合 ∑。
输出:满足 3NF 的所有关系模式的集合 S,且每个关系模式都包含一组函数依赖的集合。
步骤

  • 从 S = { ∅ } 开始,并找出集合 ∑ 的最小覆盖 ∑‘;
  • 分别将最小覆盖 ∑‘ 中的每一个函数依赖的左边和右边属性分为一组
    (重复)对于每个最小覆盖 ∑‘ 中独特的左边属性 X_i,其满足 X_i → A_1, X_i → A_2,。。。, X_i → A_k;
  • 添加关系模式 R_i = X_i ∪ { A_1 } ∪ { A_2 } 。。。 ∪ { A_k } 到集合 S 中。
  • 清除集合 S 中的冗余关系模式,比如去掉 R_i 如果 R_i ⊆ R_k。
  • 如果集合 S 中不包含一组 R_i 能作为 R 的超键,就要添加一组键,记为 R_0。
  • 把最小覆盖 ∑’ 中的每一个函数依赖映射到 S 中的每个关系模式 R 上。

第三范式分解仅仅可以减少数据冗余,但不能完全消除,还是会存在一部分的冗余,因此满足 3NF 的数据模式仍然有可能会出现数据更新异常的现象。要想避免更新异常的情况,就要使用 BC 范式或者约束更强的范式来消除所有的冗余。

你可能感兴趣的:(【数据库】数据库入门(八): 数据库规范化(Normalisation))