函数依赖与关系模式设计
函数依赖基础
函数依赖的定义
函数依赖是关系数据库设计中描述属性之间约束的核心概念:
函数依赖:如果关系 R 中任意两个元组在属性集 X 上取值相同,则它们在属性集 Y 上的取值也必须相同,记为
。 - X 称为决定因素(或左部),Y 称为依赖因素(或右部)
- X 函数决定 Y,或 Y 函数依赖于 X
- 例如:
name → addr favBeer
表示姓名决定了地址和喜欢的啤酒
逻辑蕴含:如果关系
的任意关系实例 r 都满足函数依赖 ,则称函数依赖集 F 逻辑蕴含函数依赖 ,记为 。
Armstrong公理系统
Armstrong公理系统是函数依赖的基本推理规则,可以用来推导函数依赖的所有逻辑结果:
自反律(Reflexivity)
- 如果
,则 为 F 所蕴含 - 直观理解:一个属性集总是能决定它的子集
- 如果
增广律(Augmentation)
- 如果
为 F 所蕴含,且 ,则 为 F 所蕴含 - 直观理解:如果X决定Y,那么在X和Y两边添加相同的属性Z后,关系仍然成立
- 如果
传递律(Transitivity)
- 如果
和 为 F 所蕴含,则 为 F 所蕴含 - 直观理解:依赖关系具有传递性
- 如果
函数依赖的推理规则
基于Armstrong公理系统,可以推导出以下常用的函数依赖推理规则:
合并规则
- 如果
和 ,则 - 例如:已知
和 ,可推导
- 如果
分解规则
- 如果
,则 和 - 例如:已知
,可推导 和
- 如果
伪传递规则
- 如果
和 ,则 - 例如:已知
和 ,可推导
- 如果
闭包计算
属性闭包
- 属性闭包:给定函数依赖集F和属性集X,X关于F的属性闭包(记为
)是X在F下能决定的所有属性的集合。 - 用途:
- 判断函数依赖
是否被F逻辑蕴含(检查Y是否包含在 中) - 判断属性集X是否为关系模式的超键(检查
是否等于U) - 判断属性集X是否为关系模式的候选码(检查X是否为极小的使
= U的属性集)
- 判断函数依赖
函数依赖闭包
- 函数依赖闭包:给定函数依赖集F,F的闭包(记为
)是F所逻辑蕴含的所有函数依赖的集合。 - 计算方法:通过Armstrong公理系统从F出发推导所有可能的函数依赖。
- 性质:
- 如果
,则 - 两个函数依赖集F和G是等价的,当且仅当
- 如果
闭包计算算法
属性闭包的计算算法是函数依赖理论的核心:
属性闭包计算算法:
- 初始化:令
- 迭代扩展:对于每一步
,找到所有满足 且 的函数依赖,将W中不在 中的属性添加到 中,得到 - 终止条件:当
时停止,此时 即为
示例: 计算
- 初始:
- 第一次迭代:
:加入 ,得到 :加入 ,得到
- 第二次迭代:
:加入 ,得到
- 第三次迭代:没有新属性加入,停止
- 结果:
最小函数依赖集
最小依赖集的定义
最小函数依赖集(也称为极小覆盖或规范覆盖)是一个等价于原函数依赖集F的简化版本,满足以下条件:
- 每个函数依赖的右部仅包含单个属性
- 无法移除任何函数依赖而保持等价性
- 无法将任何函数依赖的左部替换为其真子集而保持等价性
意义:最小函数依赖集消除了冗余,是设计关系模式和判断范式的基础。
最小依赖集的计算步骤
计算最小函数依赖集的步骤如下:
右部单一化
- 将每个函数依赖
拆分为一组函数依赖
- 将每个函数依赖
去除冗余依赖
- 对于每个函数依赖
,检查是否可以从F中移除而不改变 - 具体方法:计算X在
下的属性闭包,如果闭包包含A,则该依赖是冗余的
- 对于每个函数依赖
左部简化
- 对于每个函数依赖
,检查是否可以用X的真子集Z替代X - 具体方法:对于X中的每个属性B,计算
在F中的属性闭包,如果闭包包含A,则B是冗余的
- 对于每个函数依赖
计算示例
计算
右部单一化:F已经满足右部单一化
去除冗余依赖:
- 检查
:在 下, ,不包含C,所以 不是冗余的 - 检查
: ,不包含D,所以 不是冗余的 - 检查
: ,不包含E,所以 不是冗余的 - 检查
: ,包含B,所以 是冗余的,移除 - 检查
: ,包含B,所以 是冗余的,移除
- 检查
左部简化:
对于
: - 检查A:
,不包含C,所以A不是冗余的 - 检查B:
,不包含C,所以B不是冗余的
- 检查A:
对于
:B是单属性,无法简化 对于
:C是单属性,无法简化
最终结果:
关系模式的分解与范式
候选码与超键
- 超键(Superkey):关系模式R中的属性集K,若K函数决定R的所有属性,则K为R的超键。
- 候选码(Candidate Key):R的极小超键,即不包含任何真子集是超键的超键。
- 主码(Primary Key):从候选码中指定的一个,用作关系的唯一标识。
- 主属性(Prime Attribute):包含在任一候选码中的属性。
- 非主属性(Non-prime Attribute):不包含在任何候选码中的属性。
范式层次
关系模式的范式层次描述了关系模式对函数依赖的符合程度:
第一范式(1NF)
- 关系的每个属性都是原子的(不可再分)
- 所有关系数据库都满足1NF
第二范式(2NF)
- 满足1NF
- 每个非主属性完全函数依赖于每个候选码
- 消除了部分依赖
第三范式(3NF)
- 满足2NF
- 每个非主属性不传递依赖于任何候选码
- 消除了传递依赖
BC范式(BCNF)
- 对于每个非平凡函数依赖
,X都是超键 - BCNF比3NF更严格,消除了所有基于函数依赖的冗余
- 对于每个非平凡函数依赖
模式分解
模式分解是将一个关系模式分解为若干个更小的关系模式,以消除冗余和异常:
分解为BCNF的步骤:
- 找到违反BCNF的函数依赖
(X不是超键) - 计算
- 将R分解为
和 - 递归应用于
和 ,直到所有关系都满足BCNF
示例: 分解
- 检查
:A不是超键( 但A不是极小的) - 分解为
和 ,但 已包含在 中 - 检查
:CD不是超键 - 分解为
和 - 继续递归检查...
3NF合成算法: 当BCNF分解可能导致函数依赖无法保持时,可使用3NF合成算法:
- 找到F的最小覆盖
- 对
中每个函数依赖 创建一个关系模式 - 如果没有任何模式包含候选码,则添加一个只包含候选码的关系模式
- 如果某个关系模式被其他关系模式完全包含,则可以去除