模式设计
模式设计的影响
Redundancy 冗余
如学生(学生,课号,课程名称,成绩)表中,课号为课程的主键,就可以表示课程了,这时课程名称便冗余了
Anomaly 异常
在上述关系模式中,如果对该表进行插入、删除、更新操作,如果只修改了部分记录的课程名称,而忘了修改课号相同的其他课程名称,就会造成异常
Funtional dependency 函数依赖
- 在一个关系模式中,存在两个属性集合A、B,对任意两行元组,如果在A上的取值相同,那么在B上的取值也相同,则称集合A决定集合B,或集合B函数依赖于集合A
- 例如学号相同的,学院就相同;学号、课程号相同的,成绩就相同
- 设计中,我们需要寻找最小函数依赖关系。例如学号、姓名、性别、生日相同的,学院就相同,但这样显然是多余的
- A和B之间是“多对一”或“一对一”的关系
- 函数依赖是根据数据库设计给出的,而不是通过数据推导的,因为数据数量有限时可能推导错误
Key 键
key的概念
- key可以决定关系表中的所有属性
- key的子集不能决定关系表中的所有属性
- Superkey(超键):包含key的属性集合
如何确定键?
- 只有一个实体集:key就是实体集的主键
- “多对多”的实体集:关系表的key是两个实体集的主键
- “多对一”的实体集:“一”的主键不是关系表的key
Closure of FD sets 函数依赖集合的闭包
- 已知两个函数依赖S、f,如果S能够推出f,那么就称fS逻辑蕴含(logically implied)。例如
- 如果S+包括S能推出的所有集合,则称S+为S函数依赖集合的闭包
Armstrong's Axioms
- Reflexivity rule 自反律:(A,B)→A,(A,B)→B
- Augmentation rule 增广律:若A→B,那么(A,C)→(B,C)
- Transitivity rule 传递率:若A→B,B→C,那么A→C
- Union rule 结合律:若A→B,A→C,那么A→BC
- Decomposition rule 分解律:若A→BC,那么A→B,A→C
- Pseudo-transivity rule 伪传递规律:若A→B,BC→D,那么AC→D
两个函数A,B依赖关系等价的意思是A→B且B→A
求解算法
- S+= S
- 利用自反律和增广律,求出所有的函数依赖,把新的函数依赖加入S+
- 利用传递律,求出新的函数依赖,把它们加入S+
- 重复上述两个步骤,直到S+不变
已知R=(A,B,C,D,E,F),函数依赖关系:AB→C,AD→E,B→D,AF→B
求解(A,F)的闭包X:
X = (A,F)
因为AF→B,所以X = (A,B,F)
因为AB→C,所以X = (A,B,C,F)
因为B→D,所以X = (A,B,C,D,F)
因为AD→E,所以X = (A,B,C,D,E,F)
(A,F)的闭包X包含了所有的属性
且A和F分别的闭包不可能包含所有的属性
因此(A,F)是key
结合函数依赖集合的闭包求解算法和key的定义可知,暴力求解所有属性组合的闭包即可求得key,但此方法复杂度高。因此我们引入启发式算法。
启发式算法求解key
启发式规则,先1后2,符合哪个用哪个:
- 不在任何函数依赖右边出现的属性必是键的一部分
- 不在函数依赖左边出现的属性不是键的一部分
不是用这两条启发式规则就能够把所有key求出来的
已知R=(A,B,C,D,E,F),函数依赖关系:AB→C,AD→E,B→D,AF→B
只有A,F没有在函数依赖的右边出现,A,F一定是key的一部分
先计算(A,F)是否为key,如果不是,再加入其他属性计算
已知R(A,B,C,D,E),函数依赖关系:AB→CE,E→AB,C→D
所有属性都在函数依赖的右边出现了,第一条规则不适用
左边只出现了A,B,C,E,因此D肯定不是key,不需要计算含有D的集合的闭包
函数依赖集合的闭包的应用
- 判断A→B是否成立,只要判断B是否在A+里即可
已知R(A,B,C,D,E),函数依赖关系:A→B,BC→D,E→C
请问下列函数依赖关系是否成立:
1. AC→D
2. AE→C
3. BC→B
4. CE→D
1. X=(A,C)
因为A→B,所以X=(A,B,C)
因为BC→D,所以X=(A,B,C,D),成立
2. X=(A,E)
因为E→C,所以X=(A,E,C),成立
3. 自反律,成立
4. X=(C,E)
闭包即为它本身,不成立
- 求key
已知R(A,B,C,D,E),函数依赖关系A→B,BC→D,E→C
根据启发式算法第一条规则,A,E没有在右边出现,因此先计算(A,E)+
(A,E)+ = (A,E,B,C,D),因此(A,E)是key
模式求精
模式求精的关键因素
最小化冗余
Decomposition 分解
- 拆分后的表之间要有相同的属性,这样合并的时候才能连接
- 确保拆分后的表的属性集合求并后是原表的属性集合
避免信息丢失
Lossless Decomposition 无损分解
- 分解后的表再合并,必须和原来的表一模一样
保持函数依赖
- 拆分后的表的函数依赖必须在原表的函数依赖中
- 拆分后的表的函数依赖求并后是原表的函数依赖
R=(A, B, C, D, E)
FD: A→C, CD→B, B→E, E→D
R分解成R1(B, C, D)和R2(A, C, E)
R1的FD: CD→B, B→D
R2的FD:A→C
确保良好的查阅性能
Multivalued Dependency (MVD) 多值依赖
X→→Y:在一个关系表中,有两行X值相同时,交换Y的值,交换后的两行仍然出现在表中(一张表中有多个多对多关系)
多值依赖的性质
- promotion: 每个FD都是MVD
- complementation: 对称性,如果X→→Y,Z是其他所有的属性,那么X→→Z
- 分解律不成立:如果A→→BC,那么A→→B,A→→C,这是不成立的
Normal Form 范式
First Normal Form
所有的属性都是原子属性
Second Normal Form
非主属性完全依赖于key
Boyce Codd Normal Form (BCNF)
- 非平凡的函数依赖:(A1,A2,...An)→B,B不是左边集合的子集
- 要求:每一个非平凡的函数依赖,其左边属性集合是R的super key,即左边集合中有R的key
- 如果一个关系模式只有两个属性,或者没有函数依赖,则该关系模式一定符合BCNF范式
- BCNF范式只能避免部分冗余,避免信息丢失(无损分解),不能保证保持函数依赖
如果R上有一个非平凡的函数依赖X→B不满足BCNF要求怎么办?
- 求X+
- 把R分解成R1和R2
- R1 = X+
- R2 = R - (X+ - X)
- 检查R1和R2符不符合BCNF的要求,如果不符合,继续分解
R=(A, B, C, D)
FD: AB→C, C→D, D→B
List all keys for R: AB, AC, AD
//第一条规则:A一定在key里
//尝试不同的组合,得出所有的key
Is R in BCNF?
No. C→D and D→B violate BCNF.
//C和D不是super key
Decompose further until all decomposed relations are in BCNF.
For C→D, C+ = C, D, B, therefore R1=(B, C, D), R2=(A, C)
For R1, FD: C→D, D→B, key is C
D→B violates BCNF.
D+ = D, B, therefore R3=(B, D), R4=(C, D)
R2, R3, and R4 are in BCNF.
Decomposed relations: R2=(A, C), R3=(B, D), R4=(C, D)
//可以发现,分解后虽然满足BCNF范式要求,但没有保持函数依赖
3范式
按照BCNF范式的要求,对关系模式进行分解后,可能会丢失函数依赖关系。那么,我们可以对BCNF范式的要求放宽一点,引入3范式:
- prime(主属性):key中的属性都是主属性
- 要求:如果X→B,X集合不是R的super key,B也不是R的主属性,那么R违反了3范式
- 对于一个关系模式,我们总能找到无损分解,使它符合BCNF的要求;也总能找到无损、保持函数依赖地分解,使它符合3范式地要求;但不一定能找到使它符合BCNF的要求的无损、保持函数依赖的分解
已知关系模式和函数依赖集合,保持FD和无损连接3NF模式分解的算法如下:
- 求极小函数依赖集Smin和关系模式的所有keys
- 在Smin中按函数依赖左部相同原则进行分组,每个组的所有属性形成分解后的子关系模式,R1, R2, ..., Rm
- 如果某个关系模式Ri的所有属性被另一个关系模式Rj所包含,删除关系模式Ri
- 判断是否有某个key出现在其中的一个关系模式中,如果出现则结束;如果没有出现,将任意一个key也作为子关系模式Rk加入到分解后的模式中
什么是极小函数依赖集F?
- F中的任意函数依赖的右部仅含有一个属性
- F中不存在这样的函数依赖X→B,使得F与F-{X→B}等价,也就是说X→B是多余的,F的闭包和去掉X→B的闭包是相同的
- F中不存在这样的函数依赖X→B,X有真子集Z,使得F-{X→B} {Z→B}与F等价,也就是说Z→B,不需要X→B了(把过大的删去)。
S=(学号,姓名,系,系主任,课程名,成绩)
F={学号→系,学号→姓名,系→系主任,学号→系主任,(学号,姓名)→系,(学号,课程名)→成绩}
//求极小函数依赖集和所有keys
对于学号→系主任,学号→系+系→系主任即可以推导出学号→系主任,因此把这一条去掉,F的闭包不变
对于(学号,姓名)→系,学号→系,不需要姓名了,因此这条关系可以去掉
因此,Fmin={学号→系,学号→姓名,系→系主任,(学号,课程名)→成绩}
key: (学号,课程名)
//在Smin中按函数依赖左部相同原则进行分组,每个组的所有属性形成分解后的子关系模式,R1, R2, ..., Rm
R1=(学号,姓名,系)
R2=(系,系主任)
R3=(学号,课程名,成绩)
//如果某个关系模式Ri的所有属性被另一个关系模式Rj所包含,删除关系模式Ri
没有需要删除的
//判断是否有某个key出现在其中的一个关系模式中,如果出现则结束;如果没有出现,将任意一个key也作为子关系模式Rk加入到分解后的模式中
R3中包含原表中的key,分解终止
4范式
- 非平凡的多值函数依赖X→→Y
- Y不是X的子集
- X和Y不是全部的属性
- 要求:对于每个非平凡的多值函数依赖X→→Y,X是一个super key
如果有一个非平凡的多值函数依赖违背了4范式的要求,如何进行分解呢?
- R1 = (X, Y)
- R2 = R - R1
判断无损连接分解的算法
R=(A, B, C, D, E) , F={AB→C, C→D, D→E} 👉 R1=(A, B, C), R2=(C, D), R3=(D, E)
- 列出表格
- 行名和列名如图所示
- 对于每一行,以第一行为例,R1中有ABC三个属性,因此ABC列下面分别写a1, a2, a3。对于a而言,只写一个下标,意思是第几列
- a写完后,对于空着的地方,填上b,下标为行、列
- 扫描函数依赖关系
- 对于每一个关系,左部取值相同的,右部也要相同
- 如果不同,则修改右部的取值,使其相同
- 有a改成a,无a改成下标最小的b
- 对于C→D,当C=a3时,D取值不同,有a,因此全部改为a4
- 对于D→E,当D=a4时,E取值不同,有a,因此全部改为a5
- 检查是否有一行的取值全部为a
- 若有,说明这个分解是无损分解
- 若无,继续扫描函数依赖关系
- 若直到表的内容不变,还没有一行的取值全部为a,那么这个分解不是无损分解