1.如何设计一个好的关系模式
- 如果一个关系R不是“好的”形式,将它分解成一个关系集合{R1, R2,…Rn}这样
1.每个Ri是一个好的形式。
2.分解是一个无损分解 - 我们的理论以:
1.函数依赖
2.多值依赖 为基础。
2.函数依赖
- 在合法关系集合上的约束。
- 要求某一组属性的值唯一地确定另一组属性的值。
- 函数依赖关系是键概念的一般化。
- K是关系模式R的超键,当且仅当K→R。
- K是关系模式R的候选键,当且仅当K→R,但是不存在K的子集A→R。
- 函数依赖性允许我们表达不能用超键表示的约束。
3.函数依赖的使用
- 我们使用函数依赖去:
1.测试关系,看看它们在一组给定的功能依赖项下是否合法。
如果一个关系r在函数依赖集合F下是合法的,我们说r满足F
2.指定法律关系的约束
如果R上的所有法律关系都满足函数依赖F的集合,我们就说F对R成立。 - 注意:关系模式的特定实例可能满足函数依赖,即使函数依赖并不包含所有合法实例。
4.函数依赖的闭包
- 给定函数依赖的集合F, F在逻辑上暗示了某些其他的函数依赖。
例如:如果A→B和B→C,那么我们可以推断A→C。 - 由F逻辑暗示的所有函数依赖的集合是F的闭包。
- 我们用F+表示F的闭包。
- F+是F的超集。
5.BCNF
- 在BCNF中,一个关系模式R是关于一组函数依赖项F的,如果所有函数依赖项F+的形式是α→β
α→β是平凡的(β∈α)
α是R的主键 - 不存在于BCNF中的示例模式:
instr_dept (ID, name, salary, dept_name, building, budget )
因为dept_namebuilding, budget保持在instr_dept上,但是dept_name不是一个超键。
6.分解为BCNF
- 假设我们有一个关系模式R和一个非平凡依赖α→β违背了BCNF,我们把R分解为:
1.(α U β )
2.(R-(β-α))
- 在上面这个例子中,α=dept_name,β= building, budget和inst_dept被替换为:
7.BCNF和依赖关系保存
- 表达数据库一致性约束的方式:
PK、FD、Check、Assertion、Triger - 在实践中检查约束(包括功能依赖项)的代价很高,除非它们只属于一个关系
- 如果只测试分解的每个单独关系上的那些依赖关系就足够了,以确保所有功能依赖关系保持不变,那么分解就是保持依赖关系。
若每次分解都恰好是一个函数依赖,则分解保持依赖。 - 因为不可能总是同时实现BCNF和依赖项保存,所以我们考虑一种较弱的范式,称为第三范式。
8.3NF
- 3NF分解弱于BCNF,它允许第三个条件,即满足第三个条件也是符合的。α→β中的每个属性A都包含在R的一个候选码中。
注意:每个属性可能在一个不同的候选键中 - 如果一个关系在BCNF中,那么它就是在3NF中(因为在BCNF中,前面两个条件之一必须成立)。
- 第三个条件是对BCNF进行最小程度的放松,以确保依赖性保持(稍后将看到原因)。
9.标准化的目标
- 设R是一个与函数相关的集合F的关系格式。
- 判断关系方案R是否“良好”。
- 当一个关系方案R不是“好”形式时,将其分解为一组关系方案{R1, R2,…Rn}这样
1.每个关系方案都很好
2.分解是无损分解
3.最好,分解保持函数依赖。
10.BCNF有多好?
-
BCNF中有些数据库模式似乎没有得到充分的规范化
-
考虑一个关系:
inst_info (ID, child_name, phone)
一个老师可以有多部手机,可以有多个孩子
-
没有非平凡依赖,因此这个关系是BCNF的。
-
插入异常—例如,如果我们将电话981-992-3443添加到99999,我们需要添加两个元组。
-
因此,最好将inst_info分解为:
-
这意味着需要更高的标准形式,如第四标准形式(4NF),我们将在后面看到。
11.函数依赖理论
- 我们现在考虑一个形式理论,它告诉我们哪些功能依赖是由一组给定的功能依赖在逻辑上隐含的。
- 然后我们开发算法生成无损分解为BCNF和3NF
- 然后我们开发算法来测试一个分解是否保持依赖关系。
12.函数依赖的闭包
- 给定函数依赖的集合F, F在逻辑上暗示了某些其他的函数依赖。
- 由F逻辑暗示的所有函数依赖的集合是F的闭包。
- 我们用F+表示F的闭包。
- 我们可以用阿姆斯特朗公理找到所有的F+:
- 求解函数依赖闭包的方法:
13.属性集的闭包
- 给定一组属性a,定义a在F下的闭包(用a+表示)为功能上由a在F下确定的属性集。
- 求a+的算法,求a在F下的闭包:
- 例子:
- AG是候选键吗?
1.AG是超键吗? AG→R等于AG是超键
2.AG的任何子集可以函数依赖推出R吗?
14.属性闭包的用法
属性闭包算法有以下几种用法:
- 检验是不是超键
- 测试函数依赖
1.检验函数依赖α→β,只需要检查是否β是α的闭包。
2.也就是说,我们使用属性闭包计算α+,然后检查它是否包含β。
3.这是一种简单、廉价且非常有用的测试。 - 计算F的闭包
对于R中的每个属性,找到它的属性闭包,那么对于闭包中的任何属性,我们可以得到函数依赖。
15.候选键的计算
- 定义:
左部属性,只出现在F左边的属性
右部属性,只出现在F右边的属性
双部属性,出现在F两边的属性
外部属性,不出现在F中的属性 - 定理:
左部属性一定出现在任何候选码中
右部属性一定不出现在任何候选码中
外部属性一定出现在任何候选码中 - 例题:
- 具体过程是这样的:因为左部属性和外部属性一定是候选码,所以看这两个里面的属性集合的闭包是不是包含R的全部属性,是的话找到了唯一的候选码。否则,这个集合每次去单独合并一个双部属性中的元素求闭包。
15.正则覆盖
- 直观地说,F的正则覆盖是与F等价的功能依赖的“最小”集合,没有冗余依赖或冗余依赖部分。
- 准确的说就是消除没必要的函数依赖:
1.A→C,AB→C 这种情况,B是无关属性。删除AB→C,保留A→C。
2.A→C,AB→CD,这种情况C是无关属性,删除C,保留A→C,AB→D。 - 过程:
- 例题:
16.无损分解
- 看分解后的关系的自然连接是否和原来的相等。
- 如果F+中至少存在以下依赖关系之一,那么将R分解为R1和R2就是无损连接。
- 上述功能依赖关系是实现无损联接分解的充分条件。
17.保持依赖
- 设Fi是仅包含Ri中的属性的依赖F +的集合。
1.分解是保持依赖性的,如果
2.如果不是,那么检查更新是否违反功能依赖项可能需要计算连接,这是非常昂贵的。
18.依赖项保存的测试
- 为了检查依赖α→β是否在分解保持了依赖,我们这样测试(通过F作属性的闭包)
如果结果包含了β的所有属性,则函数依赖α→β是保持依赖的。 - 我们对F中的所有依赖项应用这个测试来检查一个分解是否保持依赖。
- 节约了时间,多项式时间。
19.测试BCNF
- 检查一个重要的依赖项α→β是否会导致违反BCNF。
1.计算α+(α的属性闭包)
2.验证它是否包含R的所有属性,即它是R的超键 - 简化测试:要检查关系模式R是否在BCNF中,只需检查给定集合F中的依赖项是否违反BCNF,而不是检查F+中的所有依赖项就足够了。
如果F中的任何依赖项都不会导致违反BCNF,那么F+中的任何依赖项也不会导致违反BCNF。 - 然而,在测试R分解中的关系时,仅使用F的简化测试是不正确的。
- 考虑R = (A, B, C, D, E), F = {A→B, BC→D}
1.将R分解成R1 = (A,B)和R2 = (A,C,D, E)。
2.F中的依赖项都不包含来自(A,C,D,E)的属性,所以我们可能会被误导,认为R2满足BCNF。
3.事实上,F+中的依赖关系ACD表明R2不在BCNF中。
20.BCNF分解测试
- 为了检验R的分解中的一个关系Ri是否在BCNF中。
1.关于F对Ri的限制的BCNF的任一检验Ri(即,F+中所有只包含Ri属性的fd)
2.或者使用与R保持一致的原始依赖项F,但需要进行以下测试:
对于每一组属性α∈Ri,检查α+是否不包含Ri-α的属性,或包含Ri的所有属性。
分解规则已经在上面讲过了。
21.BCNF和函数依赖
- 不总是可能的得到一个BCNF是保持函数依赖的。
- 提出3NF分解。
- 总有一个无损连接,保持依赖性分解到3NF。
22.3NF冗余
- 这个模式有一些冗余。
- 3NF中冗余问题的例子。
- 有信息重复,比如L和K存在多个l1和k1。
- 需要使用空值,例如为了去表达l2和k2这里没有相对应的J值。
23.3NF的测试
- 优化:只需检查F中的FDs,不需要检查F+中的所有FDs。
- 使用属性闭包检查每个依赖α→β,如果α是一个超键。
- 如果α不是一个超键,我们必须验证α中的每个属性是否包含在一个候选键R中。
1.这个测试相当昂贵,因为它涉及到寻找候选键
2.3NF的测试已经被证明是np困难的。
3.有趣的是,分解为第三范式(稍后介绍)可以在多项式时间内完成。
24.如何分解为3NF
25.3NF判断
- 个人理解的做法就是根据BCNF的前两个性质以及自己的第三个性质,但是要先求出候选码。关键在于候选码的求解。