一:数据依赖
在一个关系中,通过属性之间的值是否相等,体现数据之间的相互关系。
这是一种完整性约束,表示特定的属性之间的关系
1. 函数依赖
(1)定义
若R是一个关系模式,且有属性集A,B,存在函数依赖A → B :表示任意两个元组t1和t2,如果t1[A] = t2[A],则t1[B] = t2[B]成立
(2)分类
- 平凡的函数依赖:关系实例R存在函数依赖A→B,并且B是A的子集
- 非平凡的函数依赖:关系实例R存在函数依赖A→B,并且B不是A的子集
- 完全函数依赖:关系实例R存在函数依赖A→B,但是A的任何一个真子集A‘都不会出现A’→B。则B对A完全函数依赖
- 部分函数依赖:关系实例R存在函数依赖A→B,同时A存在一个真子集A‘满足A’→B。则B对A部分函数依赖
- 传递函数依赖:关系实例R存在非平凡的函数依赖A→B和函数依赖B→C,则C对A传递依赖
(3)作用
1:求超码和候选码
- 超码K:K→R
- 候选码K:K→R,且K的子集k都不会满足k→R
- 对于F的每个函数依赖,进行画图
- 通过传递和增补,确定候选码
2:检查关系R在给定的函数依赖集A→B下是否合法
- 在属性集A中,存在两个元组属性值相同,并且在属性集B中,上面两个元组的属性值也相同,此时合法
- 在属性集A中,不存在属性值相同的元组,此时合法
3:对合法的关系R指定约束
根据R的语义判断
(4)闭包F+
给定函数依赖集F,存在其他函数被F逻辑蕴含。被逻辑蕴含的全体函数依赖的集合为F的闭包F+
获取闭包:Armstrong公理
- 自反律:即平凡的函数依赖
- 增补律:若A→B,则AC→BC,AC→B
- 传递律:若A→B,B→C,则A→C
- 合并律:若A→B,A→C,则A→BC
- 分解律:若A→BC,则A→B,A→C
- 伪传递律:若A→B,BC→D,则AC→D
计算闭包:
- 将F依赖函数集放入F+
- 不断对F+中的每个依赖函数使用自反律和增补律,再将结果放入F+
- 不断对F+中的一对依赖函数,判断是否可以使用传递律,若可以则将结果放入F+
(5)属性集的闭包A+
对于一个属性集A,在函数依赖集F下由A函数确定的所有属性集合A+
- 判断A是否为超码:判断关系R的所有属性是否包含于A的闭包A+中
- 判断A是否为候选码:
- 判断A是否为超码
- 判断A的子集的闭包是否不包含R的所有属性
- 判断A→B是否属于F的闭包:判断A的闭包是否包含B的所有属性
- 计算闭包F+:对于R的每个属性A,计算属性集的闭包A+,从而输出A→A+子集属性
计算闭包:
- 将属性集A放入A+
- 对函数依赖集F,如果B→C,并且B是A+的子集,那么把C加入到A+中(C∪A+)
- 直到A+不再变化
(6)正则覆盖Fc
与F等价的极小的函数依赖集合
特点:
- 函数依赖不包含无关属性
- 左半部分唯一
判断条件
- 存在可被其他函数依赖推导出的函数依赖,可删除(传递律、增补律、自反律)
- 函数依赖的左半部分有属性冗余,删除属性(左边分解后回到第一步判断)
- 函数依赖的右半部分有属性冗余,删除属性(右边分解后回到第一步判断)
无关属性
对于函数依赖F1=A→B
- 如果A存在属性A1
剩余函数依赖集F2 = F - F1
剩余属性函数依赖F3 = (A-A1)→B
如果F逻辑蕴含F2∪F3,则A1在A中是无关属性- 在F的基础上,计算A去掉属性A1后的闭包A+
- 如果A+包含B,则属性A1是无关属性
- 如果B存在属性B1
剩余函数依赖集F2 = F - F1
剩余属性函数依赖F3 = A→(B-B1)
如果F2∪F3逻辑蕴含F,则B1在B中是无关属性- 获取F2∪F3,在此基础上计算A的闭包A+
- 如果A+里面包含属性B1,则B1是无关属性
计算正则覆盖
- 对F的函数依赖利用合并规则替换
- 利用判断条件,找出含有无关属性的函数依赖,去掉无关属性
- 直到F不再变化
2. 多值依赖
(1)定义
若R是一个关系模式,且有属性集A,B,存在多值依赖A→→B:在某个关系中Ri中,对所有满足t1[A]=t2[A]的元组对,存在t3 t4:
- A属性全部相同
- t1[A] = t2[A] = t3[A] = t4[A]
- B属性部分相同
- t3[B] = t1[B]
- t4[B] = t2[B]
- 剩余属性C=R-A-B部分相同
- t3[C] = t2[C]
- t4[C] = t1[C]
(2)平凡多值依赖
- B是A的子集
- A∪B=R
(3)子集多值依赖
如果R分解为A,B,C
如果(A1,B1,C1)和(A2,B2,C2)在R中,则(A1,B1,C2)和(A1,B2,C1)也在R中。
此时A→→B,A→→C,B和C相互独立
二:规范化
1. 模式分解
将关系模式R分解为R1,R2…Ri
要求:
(1)属性一致:
原关系模式R的所有属性都必须出现在分解后的模式中( A = A1∪A2)
(2)无损连接分解:
- R1⋈R2 = R
- 分解后各个模式的公共属性是某个关系模式的超码。(F+中至少存在:R1∩R2 → R1或R1∩R2 → R2)
- 找出公共属性集
- 找出公共属性集对应的闭包
- 查看闭包是否包含某个关系
(3)保持依赖:
有效检查更新操作,允许分别验证子关系模式Ri(Fi是只包含Ri属性的函数依赖集)
- Fi 是 F+ 的子集
- 原关系模式R的函数依赖集闭包都必须出现在分解后模式的函数依赖集。即(F1∪F2)+=F+
- 若F = A→B,先将A加入结果集
- 找出每个关系模式Ri与结果集的公共部分,求闭包
- 找出每个关系模式Ri与闭包的公共部分,加入到结果集中
- 直到结果集不在变化。若结果集包含B的所有属性,则该函数依赖得到保持
(4)没有冗余
2. 关系范式
(1)第一范式
关系模式R的所有属性的域是原子的,不可分的。
非原子:
- 复合属性:把子属性作为新属性
- 多值属性:把每个值作为新元组
- 复杂数据类型
缺点:
- 数据冗余
- 修改不一致
- 插入、删除异常
(2)第二范式
关系模式R属于1NF,且每个非主属性都完全依赖于码。
对于R只检查F的每个函数依赖,对于R的分解检查F+的所有函数依赖:
- 该函数依赖为平凡函数依赖(B是A的子集)
- A是关系模式R的超码(R是A的闭包的子集)
- B除去和A的公共属性(即B-A)的剩余属性a都包含在R的候选码中(a是主属性)
- B是超码的闭包的子集
特点:
- 允许A不是超码(B是主属性或者B可以由超码推出)
- 信息冗余,需要空值
- 分解无损,保持依赖
分解关系R成为2NF
- 确定F的正则覆盖Fc
- 检查Ri是否包含函数依赖A,B。如果没有则添加新的关系Ri=(A,B)
- 判断Ri是否包含R的候选码。如果没有则添加新的关系Ri=(候选码)
- R=(R1…R2…Ri),检查并删除冗余子集
(3)第三范式
关系模式R属于2NF,且每个非主属性都不会传递依赖于码
对于R只检查F的每个函数依赖,对于R的分解检查F+的所有函数依赖:
- 该函数依赖为平凡函数依赖(B是A的子集)
- A是关系模式R的超码(R是A的闭包的子集)
- B除去和A的公共属性(即B-A)的剩余属性a都包含在R的候选码中(a是主属性)
特点:
- 允许A不是超码(B是主属性)
- 信息冗余,需要空值
- 分解无损,保持依赖
分解关系R成为3NF
- 确定F的正则覆盖Fc
- 检查Ri是否包含函数依赖A,B。如果没有则添加新的关系Ri=(A,B)
- 判断Ri是否包含R的候选码。如果没有则添加新的关系Ri=(候选码)
- R=(R1…R2…Ri),检查并删除冗余子集
(4)BC范式
对于R只检查F的每个函数依赖,对于R的分解检查F+的所有函数依赖:
- 该函数依赖为平凡函数依赖(B是A的子集)
- A是关系模式R的超码(R是A的闭包的子集)
特点:
- A必须是超码
- 信息不会冗余
- 分解无损,不一定保持依赖
分解关系R成为BCNF:
- 检查Ri的F+(或R的F),是否不满足条件
- 在不满足条件的关系Ri中,去除函数依赖的右部分B:R1=Ri-B
- 左右部分自成一个关系:R2=(A,B)
- R = (R-Ri)∪R1∪R2,
- 继续检查,直到所有Ri满足BCNF
(5)第四范式
对于R只检查D的每个多值依赖,对于R的分解检查D+的所有多值依赖:
- 该多值依赖为平凡多值依赖(B是A的子集)
- A是关系模式R的超码(R是A的闭包的子集)
分解关系R成为4NF:
- 检查Ri的D+(或R的D),是否不满足条件
- 在不满足条件的关系Ri中,去除多值依赖的右部分B:R1=Ri-B
- 左右部分自成一个关系:R2=(A,B)
- R = (R-Ri)∪R1∪R2,
- 继续检查,直到所有Ri满足4NF