关系型数据库设计
设计规范
有损分解
有损分解(lossy decomposition):无法通过自然连接重建原始关系元组的分解
将 employee(ID, name, street, city, salary)分解为 employee_attr1(ID, name)和 employee_attr2(name, street, city, salary)
name 无法作为 employee_attr2 关系的主码,有可能会重名
无损分解
无损分解(lossless decomposition):可以通过自然连接重建原始关系元组的分解
$$
r=\prod_{A,B}(r)\bowtie \prod_{B,C}(r)
$$
函数依赖
成立条件
假设 $r(R)$ 是一个关系模式,$\alpha\subseteq R,\beta\subseteq R$,模式 $R$ 上的函数依赖:
$$
\alpha \rightarrow \beta
$$
成立条件为:对于任意关系实例 $r$ 中任意两个元组 $t_1$ 和 $t_2$,若两者的属性(集)$\alpha$ 取值相同,那么它们的属性(集)$\beta$ 取值也相同,即:
$$
t_1[\alpha]=t_2[\alpha] \Rightarrow t_1[\beta]=t_2[\beta]
$$
称为 $\alpha$ 函数确定 $\beta$;$\beta$ 函数依赖于 $\alpha$
函数依赖和码
超码
在某个关系中,一个或多个元素的集合 ${A_1,A_2,\dots,A_n}$ 函数决定该关系中的其他全部属性,则称该属性为该关系的超码
若属性组 $K$ 满足 $K\Rightarrow R$,则 $K$ 是关系模式 $R$ 的超码($K$ 函数确定 $R$)
候选码
若集合 ${A_1,A_2,\dots,A_n}$ 的任何真子集均不能函数决定该关系中的其他属性,则此时集合 ${A_1,A_2,\dots,A_n}$ 是最小的超码,即候选码
$$
K\rightarrow R: \text{且不存在}: \alpha\subset K: \text{满足}: \alpha \rightarrow R
$$
外码
若关系模式 $R$ 中属性(组)$X$ 是另一类关系模式的主码,则称 $X$ 是 $R$ 的外码
函数依赖是码的概化
| 概念 | 决定什么? | 形式 |
|---|---|---|
| 码(Key) | 一个属性集 唯一确定整条记录 | $K\rightarrow R$ |
| 函数依赖(FD) | 一个属性集 唯一确定另一属性集 | $X\rightarrow Y,\text{其中} Y\subseteq R$ |
函数依赖使用
函数依赖在关系实例和关系模式上的体现区别:
- 如果关系实例 $r$ 在函数依赖集 $F$ 上合法,则称 $r$ 满足 $F$
- 如果模式 $R$ 上的所有合法关系实例都满足函数依赖集 $F$,则 $F$ 在关系模式 $R$ 上成立
注意:即使函数依赖并没有对关系模式 $r(R)$ 的所有合法实例成立,这个关系模式的其中一个具体实例 r 可能满足函数依赖
平凡
有些函数依赖被称为平凡(trivial)的,因为它们在所有关系中都是满足的(用于描述在函数依赖中一种必然成立、无需额外信息即可判断为真的情况)
例如:name -> name;ID, name -> ID
通常,如果 $\beta \subseteq \alpha$,那么 $\alpha \rightarrow \beta$ 是平凡的函数依赖
- 若 $\alpha \rightarrow \beta$,则称 $\alpha$ 为决定因素
- 若 $\alpha \rightarrow \beta$ 但 $\beta \not\subseteq \alpha$,则 $\alpha \rightarrow \beta$ 是非平凡的函数依赖
部分依赖:函数依赖 $\alpha \rightarrow \beta$ 称为部分依赖的条件是:存在 $\alpha$ 的真子集 $\gamma$,使得 $\gamma \rightarrow \beta$
平凡的例子:
- ${A, B} \rightarrow A$:因为 $A \subseteq {A, B}$,所以这是平凡的。
- ${A, B, C} \rightarrow {B, C}$:右边是左边的子集,平凡。
- $A \rightarrow A$:最简单的平凡依赖。
非平凡的例子:
- ${A, B} \rightarrow C$:如果 $C \notin {A, B}$,这就是非平凡的函数依赖。
- $A \rightarrow B$(且 $B \neq A$):也是非平凡的。
完全非平凡(有时也称“真正非平凡”):
- 如果 $\alpha \cap \beta = \emptyset$(即左右两边没有公共属性),则称为完全非平凡的函数依赖
- 例如:${\text{学号}} \rightarrow {\text{姓名}}$,通常学号和姓名无交集,属于完全非平凡。
平凡的函数依赖总是成立,无论数据内容如何。它们不携带任何关于数据语义的有用信息。
在研究函数依赖的推理(如 Armstrong 公理)、计算闭包或进行规范化时,我们主要关注非平凡的函数依赖,因为它们反映了数据之间的实际约束。
数据库设计和规范化过程中,可以忽略平凡依赖,重点分析非平凡依赖是否导致冗余或异常。
平凡函数依赖 = 右边 ⊆ 左边 → 必然成立,无信息量。
非平凡函数依赖 = 右边 ⊈ 左边 → 可能反映真实业务规则,需重点关注。
闭包
函数依赖的闭包(Closure)是关系数据库规范化理论中的一个核心概念,主要用于:
- 判断某个函数依赖是否被隐含(即是否可以从已知依赖推导出来);
- 计算属性集的“决定能力”;
- 求候选码;
- 进行模式分解等。
闭包分为两类:
- 函数依赖集的闭包 $F^+$
- 属性集的闭包 $X^+$
函数依赖集的闭包
给定一个关系模式 $R$ 和其上的一组函数依赖 $F$,$F^+$(读作 “F plus”)表示 由 $F$ 逻辑蕴含(可推导出)的所有函数依赖的集合。
换句话说,$F^+$ 是在 Armstrong 公理系统下,从 $F$ 出发能推导出的所有合法函数依赖的全集。
- $F \subseteq F^+$
- $F^+$ 可能非常大(指数级),通常不显式计算整个 $F^+$。
- 实际应用中更常使用 属性集的闭包 来间接判断某个 FD 是否属于$F^+$。
属性集的闭包
这是最常用、最实用的闭包概念。
给定属性集 $X \subseteq R$ 和函数依赖集 $F$,$X^+$(读作 “X plus”)表示 在 $F$ 的约束下,由 $X$ 函数决定的所有属性的集合。
即:
$$
X^+ = { A \in R \mid X \rightarrow A \text{ 被 } F \text{ 逻辑蕴含} }
$$
逻辑蕴含
函数依赖的逻辑蕴含(Logical Implication of Functional Dependencies)回答了这样一个问题:给定一组已知的函数依赖 $F$ ,能否推导出另一个函数依赖 $X\rightarrow Y$
如果能,就认为:$F$ 逻辑蕴含 $X\rightarrow Y$
记作:
$$
F \models X \rightarrow Y
$$
推理规则
Armstrong 公理:
- 自反律:如果 $\beta \subseteq \alpha$,则有 $\alpha \rightarrow \beta$
- 增补律:如果 $\alpha \rightarrow \beta$,则有 $\gamma \alpha \rightarrow \gamma\beta$
- 传递律:如果 $\alpha\rightarrow\beta$ 且 $\beta\rightarrow\gamma$,则有 $\alpha\rightarrow\gamma$
可以使用 Armstrong 公理推导函数依赖集的闭包
- $F^+$:相当于可达边集
- $X^+$:相当于可达点集
计算 $F^+$
- 从 $F$ 出发
- 遍历现有函数依赖集中的单个函数依赖,应用自反律和增补律
- 遍历现有函数依赖集中的一对函数依赖,应用传递律(if can)
- 重复,直到结果不再变化
二级定理:
- 合并律:若有 $\alpha\rightarrow\beta$ 且 $\alpha\rightarrow\gamma$,则有 $\alpha\rightarrow\beta\gamma$
- 分解律:若有 $\alpha\rightarrow\beta\gamma$,则有 $\alpha\rightarrow\beta$ 且 $\alpha\rightarrow\gamma$
- 伪传递律:若有 $\alpha\rightarrow\beta$ 且 $\gamma\beta\rightarrow\delta$,则有 $\alpha\gamma\rightarrow\delta$
计算 $X^+$
遍历函数依赖集 $F$,所有出现在 $F$ 中的函数依赖(记为 $\alpha\rightarrow\beta$),若 $\alpha$ 出现在给定的属性集 $X$ 中,则将其加入 $X^+$
result := x
while (result is changed) {
for each a->b in F {
if a in result {
result += b
}
}
}
return result
用途
- 判断超码:如果 $X^+$ 包含 $R$ 中所有属性,则 $X$ 为超码
- 验证函数依赖:
- 检验函数依赖 $\alpha\rightarrow\beta$ 是否成立(即是否在 $F^+$ 中)
- 只需计算 $X^+$,查看是否包含 $\beta$
- 计算 $F$ 闭包:
- 对于 $\alpha\subseteq R$,计算闭包 $\alpha^+$
- 遍历 $\alpha^+$(即对任意 $\beta\subseteq\alpha^+$),输出一个函数依赖 $\alpha\rightarrow\beta$
规范化(Normalization)
目标
在关系模式不是“好”的情况下,将其分解为关系模式集 ${R_1,R_2,\dots,R_n}$,关系模式集满足:
- 每个关系模式都是“好”的:无数据冗余,符合一定范式
- 分解是无损连接分解
- 最好能使分解保持依赖
范式 Normal Form
$$
1NF\subset 2NF \subset 3NF \subset BCNF \subset 4NF \subset 5NF
$$
某一关系模式 $R$ 最高属于第 $n$ 范式,则可称为 $R\in nNF$
第一范式
- 如果某个域的元素被认为是不可分的单元,那么这个域就是原子的
- 如果一个关系模式 $R$ 的所有属性域都是原子的,称关系模式 $R$ 属于第一范式
- 非原子的值会造成复杂存储和数据冗余
第二范式
建立在第一范式(1NF)的基础上,旨在消除部分函数依赖,从而减少数据冗余和更新异常
- 若关系模式 $R\in 1NF$,且在 $F^+$ 中每一个非主属性完全函数依赖于候选码,则 $R\in 2NF$
部分依赖
- 如果主键是复合的(比如由两个或更多属性组成),
- 而某个非主属性只由主键的一部分决定,而不是整个主键,
- 这就是“部分依赖”。
选课(学号, 课程号, 学生姓名, 课程名称, 成绩)
候选码:{学号,课程号};非主属性:学生姓名、课程名称、成绩
- {学号,课程号}->成绩:完全依赖
- 学号->学生姓名:部分依赖
- 课程号->课程名称:部分依赖
问题:
- 学生姓名随学号重复存储(选了多门课就存多次)→ 数据冗余
- 修改学生姓名需更新多行 → 更新异常
- 删除某门课可能误删学生信息 → 删除异常
第三范式
在第二范式(2NF)的基础上进一步消除传递函数依赖,从而更有效地减少数据冗余和更新异常
对 $F^+$ 中所有形如 $\alpha\rightarrow\beta$ 的函数依赖中,至少有以下条件之一成立:
- $\alpha\rightarrow\beta$ 是一个平凡的函数依赖(即 $\beta\subseteq\alpha$)
- $\alpha$ 是 $R$ 的一个超码
- $\beta-\alpha$ 中的每个属性 $A$ 都包含在 $R$ 的候选码中(可能包含在不同的候选码)
第三个条件是 BCNF 的一个最小放宽:3NF 允许主属性被非超码决定,而 BCNF 不允许。
Student(学号, 姓名, 系名, 系主任)
函数依赖:
- 学号->系名
- 系名->系主任
学号是候选码,系名、系主任是非主属性。系主任不直接依赖于候选码,而是通过系名传递依赖于候选码
这种依赖会导致:
- 同一系的所有学生都重复存储“系主任” → 冗余;
- 更换系主任需更新多行 → 更新异常。
Boyce-Codd 范式(BCNF)
BC 范式比第三范式(3NF)更严格,旨在彻底消除由函数依赖引起的冗余和异常。不仅处理非主属性,还要确保所有属性(包括主属性) 都不会因非超码的决定因素而产生冗余。
一个关系模式 $R$ 属于 BCNF,当且仅当:对于 $R$ 上的每一个非平凡的函数依赖 $X \rightarrow Y$ (即 $Y \not\subseteq X$)
- $X$ 必须是 $R$ 的一个超码
| 特性 | 第三范式(3NF) | BCNF |
|---|---|---|
| 要求 | 对每个 FD $X \rightarrow A$,满足: 1. $X$ 是超码,或 2. $A$ 是主属性(属于某个候选码) |
对每个 FD $X \rightarrow A$,必须满足: $X$ 是超码 |
| 宽松程度 | 较宽松(允许主属性被非超码决定) | 更严格(不允许任何非超码作为决定因素) |
| 冗余控制 | 可能仍有少量冗余(主属性间) | 基本消除所有由 FD 引起的冗余 |
函数依赖理论
正则覆盖
- 函数依赖集可能存在冗余依赖(这些依赖可以从其他依赖中推导出来)
- 函数依赖集的一部分也可能是冗余的
令 $F$ 的正则覆盖 $F_c$ 没有任何冗余依赖或存在冗余部分的依赖
$F_c$ 具有和 $F$ 相同的函数依赖集闭包。其意义在于:验证 $F_c$ 比验证 $F$ 更加容易、3NF 算法必备
${A\rightarrow B,B\rightarrow C, A\rightarrow C}$
其中 $A\rightarrow C$ 是冗余的,可以由另两个函数依赖推出
${A\rightarrow B,B\rightarrow C, A\rightarrow CD}$
可以简化为 ${A\rightarrow B,B\rightarrow C, A\rightarrow D}$
${A\rightarrow B,B\rightarrow C, AC\rightarrow D}$
可以简化为 ${A\rightarrow B,B\rightarrow C, A\rightarrow D}$
无关属性
如果去除函数依赖中的一个属性不改变该函数依赖集的闭包,则称该属性是无关属性(extraneous)
形式化定义:考虑函数依赖集 $F$ 及 $F$ 中的函数依赖 $\alpha\rightarrow\beta$
- 如果 $A\in \alpha$ 且 $F$ 逻辑蕴含$(F-{\alpha\rightarrow \beta})\cup {(\alpha-A)\rightarrow \beta}$,则属性 $A$ 在 $\alpha$ 中是无关的
- 如果 $A\in \beta$ 且函数依赖集 $(F-{\alpha\rightarrow \beta})\cup {\alpha\rightarrow (\beta-A)}$ 逻辑蕴含 $F$,则 $A$ 在 $\beta$ 中是无关的
也就是去掉该函数依赖,或者去掉函数依赖一侧的元素 $A$,这样形成的函数依赖仍然能保持闭包不变
给定 $F={A\rightarrow C, AB\rightarrow C}$
对于 $AB\rightarrow C$ 去掉 $B$,得到 $A\rightarrow C$,因为 ${A\rightarrow C, AB\rightarrow C}$ 逻辑蕴含 $A\rightarrow C$,所以 $B$ 是 $AB\rightarrow C$ 中的无关属性
给定 $F={A\rightarrow C, AB\rightarrow CD}$
对于 $AB\rightarrow CD$,去掉 $C$ 得到 $AB\rightarrow D$,再加上原来的 ${A\rightarrow C}$,得到的新函数依赖集逻辑蕴含 $F$,即 $C$ 是 $AB\rightarrow CD$ 的无关属性
无关属性的验证
考虑函数依赖集 $F$ 及 $F$ 中的函数依赖 $\alpha\rightarrow\beta$
验证属性 $A\in \alpha$
- 使用 $F$ 中的函数依赖计算属性集闭包 $(\alpha-A)^+$
- 如果该属性集闭包中包含 $\beta$,则 $A$ 在 $\alpha$ 中是多余属性
验证属性 $A\in \beta$
- 使用函数依赖集 $F’=(F-{\alpha\rightarrow\beta})\cup {\alpha\rightarrow (\beta-A)}$ 计算 $\alpha’^+$
- 如果 $\alpha^+$ 包含 $A$,则 $A$ 在 $\beta$ 中是多余属性
正则覆盖的计算
Fc = F
do {
使用合并律将 Fc 中的 a1->b1 和 a1->b2 替换为 a1->b1b2(寻找左侧相同)
在 Fc 中找出在 a 或 b 中含无关属性的函数依赖 a->b
若发现无关属性,将其从 Fc 的 a->b 中删除
} while (Fc is changed);
$F$ 的正则覆盖 $F_c$ 是一个函数依赖集,具有如下特性:
- $F$ 逻辑蕴涵 $F_c$ 中的所有函数依赖
- $F_c$ 逻辑蕴涵 $F$ 中的所有函数依赖
- $F_c$ 中任何函数依赖都不含无关属性
- $F_c$ 中函数依赖的左半部都是不同的
示例:$R = (A, B, C),F = { A \rightarrow BC,B \rightarrow C,A \rightarrow B,AB \rightarrow C }$
初始化 $F_c=F={ A \rightarrow BC,B \rightarrow C,A \rightarrow B,AB \rightarrow C}$
寻找左侧相同的函数依赖:$A\rightarrow BC$ 和 $A\rightarrow B$,替换为 $A\rightarrow BC$,此时 $F_{c1}={ A \rightarrow BC,B \rightarrow C,AB \rightarrow C}$
寻找无关属性,先尝试删去左侧元素,再删去右侧元素
- 对于 $AB\rightarrow C$,$\alpha=AB,\beta=C$
- 删去 $A$,对 $(AB-A)^+=B$ 用 $F$ 中的函数依赖计算属性闭包
- $R’={B,C}$,$R’$ 包含 $C$,即 $R’$ 逻辑蕴含 $\beta$
- 所以 $A$ 是该函数依赖的无关属性,删去得到 $B\rightarrow C$
- 更新 $F_{c2}={A\rightarrow BC, B\rightarrow C}$
- 也可以删去 $B$,也可以得到 $B$ 是无关属性,因为本质上都可以由 $A\rightarrow BC$ 推理得到,二者选一即可
- 删去 $A$,对 $(AB-A)^+=B$ 用 $F$ 中的函数依赖计算属性闭包
- 对于 $A\rightarrow BC$:$\alpha=A,\beta=BC$
- 删去 $B$,对 $F’=(F-{A\rightarrow BC})\cup {A\rightarrow C}={A\rightarrow C, B\rightarrow C}$ 计算属性闭包(删除原本函数依赖,加上新函数依赖)
- $R’’={A,B,C}$ 包含 $B$,所以 $B$ 是无关属性
- 更新 $F_{c3}={A\rightarrow B, B\rightarrow C}$
- 删去 $B$,对 $F’=(F-{A\rightarrow BC})\cup {A\rightarrow C}={A\rightarrow C, B\rightarrow C}$ 计算属性闭包(删除原本函数依赖,加上新函数依赖)
最后结果即为:$F_{c}={A\rightarrow B, B\rightarrow C}$
无损分解
对于 $R=(R_1,R_2)$,要求模式 $R$ 上的所有可能关系 $r$ 都有:
$$
r=\prod_{R_1}(r)\bowtie \prod_{R_2}(r)
$$
如果下面的依赖中至少有一个属于 $F^+$,那么将 $R$ 分解为 $R_1$ 和 $R_2$ 是无损连接分解:
- $R_1\cap R_2\rightarrow R_1$
- $R_1\cap R_2\rightarrow R_2$
- $R_1\cap R_2$ 是 $R_1$ 或 $R_2$ 的超码
上述函数依赖测试只是无损连接分解的一个充分条件;只有当所有约束都是函数依赖时,它才是必要条件
$R={A,B,C},F={A\rightarrow B, B\rightarrow C}$
方式一:$R_1=(A,B),R_2=(B,C)$
- 检验:$R_1\cap R_2={B},B\rightarrow BC$
方式二:$R_1=(A,B),R_2=(A,C)$
- 检验:$R_1\cap R_2={A},A\rightarrow AB$
保持依赖
$F$ 为模式 $R$ 上的一个函数依赖集,$R_1 ,R_2 , \dots, R_n$ 为 $R$ 的一个分解。$F$ 在 $R_i$ 上的限定是 $F ^+$ 中所有只包含 $R_i$ 中属性的函数依赖的集合$F_i$
令 $F’=F_1\cap F_2\cap\dots\cap F_n$,$F’$ 是模式 $R$ 上的一个函数依赖集
- 如果 $(F’)^+=F^+$ 成立,则该分解是保持依赖的
- 具有上述性质的分解称为保持依赖的分解
即不需要进行表的连接,就可以查询到每个函数依赖对应的数据
检验
当 $R$ 分解成 $R_1 ,R_2 , \dots, R_n$ 后,验证每一个函数依赖 $\alpha\rightarrow\beta$ 是否被保持:
result = a
while (result is changed) {
for each Ri {
t = (result ∩ Ri)^+ ∩ Ri
result = result ∪ t
}
}
- 如果 result 包含 $\beta$ 中的所有属性,那么函数依赖 $\alpha\rightarrow\beta$ 被保持
$R={A,B,C},F={A\rightarrow B, B\rightarrow C}$
方式一:$R_1=(A,B),R_2=(B,C)$,保持依赖
方式二:$R_1=(A,B),R_2=(A,C)$,不保持依赖
BCNF 分解算法
BCNF 是关系数据库规范化中的一种高级范式,用于消除函数依赖引起的冗余和异常。一个关系模式 $R$ 属于 BCNF,当且仅当对于其每一个非平凡的函数依赖 $X \rightarrow Y$,$X$ 都是 $R$ 的超码。
当关系模式不满足 BCNF 时,可通过以下步骤进行无损连接的 BCNF 分解:
分解步骤
输入:一个关系模式 $R$ 及其函数依赖集 $F$
输出:$R$ 的一个 BCNF 分解 $\rho = {R_1, R_2, \dots, R_n}$,满足无损连接性
检查当前关系模式 $R$ 是否满足 BCNF:
- 对 $F^+$ 中的每一个非平凡函数依赖 $X \rightarrow Y$:
- 若 $X$ 不是 $R$ 的超码,则 $R$ 不满足 BCNF,需进行分解
- 对 $F^+$ 中的每一个非平凡函数依赖 $X \rightarrow Y$:
若 R 不满足 BCNF:
- 找到一个违反 BCNF 的函数依赖 $X \rightarrow Y$(即 $X$ 不是超码)
- 将 $R$ 分解为两个子模式:
- $R_1 = X \cup Y$
- $R_2 = R − (Y − X)$(即保留 $X$ 和其余不在 $Y$ 中的属性)
- 对 $R_1$ 和 $R_2$ 分别递归执行 BCNF 分解
若 $R$ 已满足 BCNF:
- 将 $R$ 加入结果分解集合 $\rho$
最终得到的分解 $\rho$ 满足:
- 每个子模式都属于 BCNF
- 分解具有无损连接性(但不一定保持函数依赖)
注意事项
- BCNF 分解总是可以达到无损连接,但可能无法保持所有原始函数依赖
- 分解结果可能不唯一,取决于选择违反 BCNF 的函数依赖的顺序
- 实际应用中,若保持依赖更重要,可考虑使用 3NF 而非 BCNF
示例
$R=(A, B, C, D, E),F={A\rightarrow BC,CD\rightarrow E,B\rightarrow D,E\rightarrow A}$
对于每个函数依赖,判断左侧是否为 $R$ 的超码
先找出所有超码:$(A),(E),(CD)$,就是判断能否从一个左侧元素集开始扩展到整个模式 $R$
所以只有 $B\rightarrow D$ 左侧不是 $R$ 的超码,不满足 BCNF,需要进行分解
分解为:
- $R_1=X\cup Y={B,D}$
- $R_2=R-(Y-X)={A,B,C,E}$
根据新的模式集和 $F$,判断是否满足 BCNF,注意此时的 $F$ 需要根据新的模式集删去不存在的元素
如:
- 对于 $R_1$,$F_1={B\rightarrow D}$,因为其他 $A,C,E$ 都不存在了,而 $B$ 是 $F_1$ 的超码,所以 $R_1$ 满足 BCNF,不需要再分解
- 对于 $R_2$,$F_2={A\rightarrow BC, E\rightarrow A}$,可以发现 $E$ 是超码,但是 $A$ 不是,所以对于 $A\rightarrow BC$ 还需要进行分解
分解:
- $R_{21}=X\cup Y={A, B, C}$,$F_{21}={A\rightarrow BC}$,$A$ 为超码,满足 BCNF
- $R_{22}=R_{2}-(Y-X)={A,E}$,$F_{22}={E\rightarrow A}$,$E$ 为超码,满足 BCNF
所以综上,需要将 $R$ 分解为:${(B,D),(A,B,C),(A,E)}$
3NF 分解
第三范式(3NF)是关系数据库规范化中的一个重要级别,它在保留函数依赖的前提下,有效减少数据冗余和更新异常。一个关系模式 $R$ 属于 3NF,当且仅当对于其每一个非平凡函数依赖 $X \rightarrow A$(其中 $A$ 是单个属性),以下至少一项成立:
- $X$ 是 $R$ 的超码,或
- $A$ 是主属性(即 $A$ 属于某个候选码)
与 BCNF 不同,3NF 允许某些非超码决定主属性,因此更容易在保持函数依赖的同时实现无损连接分解。
分解目标
- 输入:关系模式 $R$ 及其函数依赖集 $F$
- 输出:$R$ 的一个分解 $\rho = {R_1, R_2, \dots, R_k}$,满足:
- 每个 $R_i$ 属于 3NF
- 分解具有无损连接性
- 分解保持函数依赖
分解步骤(基于规范覆盖的合成算法)
计算 $F$ 的最小覆盖(也称规范覆盖)$F_c$:
- 合并右部相同的依赖(如 $X\rightarrow A$, $X\rightarrow B$ 合并为 $X\rightarrow AB$)
- 去除左部冗余属性(若 $(X−A)\rightarrow Y$ 仍能推出原依赖,则 $A$ 冗余)
- 去除冗余依赖(若移除某依赖后 $F^+$ 不变,则该依赖冗余)
对 $F_c$ 中的每个函数依赖 $X \rightarrow A_1A_2\dots A_n$:
- 创建一个关系模式 $R_i = X \cup {A_1, A_2, \dots, A_n}$
检查是否已有模式包含 $R$ 的某个候选键:
- 若没有,则任选一个候选键 $K$,添加一个新关系模式 $R_k = K$
(可选)去除被其他模式包含的关系模式(即若 $R_i \subseteq R_j$,则删除 $R_i$)
特点说明
- 该算法保证分解结果既保持函数依赖又具有无损连接性
- 所有生成的子模式自动满足 3NF
- 最小覆盖确保了分解的简洁性和无冗余
- 添加候选键是为了保证无损连接(因为仅靠依赖可能无法覆盖全部属性或重建原关系)