9.关系数据库设计—— BCNF 范式
回顾第一、第二、第三范式
- 第一范式:表中没有多值属性
- 第二范式:防止候选键的真子集决定非子属性
- 第三范式:防止非键决定非主属性
Boyce-Codd Normal Form( BCNF )
- R 符合 BCNF 当:
- 对任意一个非平凡依赖,左侧为 super key
- BCNF 数据实际存储不会有数据重复
- 如果一个 relation 满足 BCNF,则也满足 1, 2 ,3 NF
- 一句话概括:非候选键不能决定任何属性
BCNF 例子
- 若存在 C → A,则违背 BCNF ,主键的一部分被其他属性决定,应该分解成 AC,BCDE
- 首先找出所有的 candidate keys:BC and EC
- { B, C } → { E },没有违背 BCNF
- { E } → { B } 违背了 BCNF,因为 E 不是一个键
- 为了实现 BCNF 对 relation 进行分解:
- R1( B, E ) 和 R2( C, E ),交集属性 E 为其中一个关系 R1 的键,所以该分解是无损的
- 用 outer join 复原分解前的表格
![image]()
- 这个分解是依赖保留的吗?
- 不是,我们丢失了 { B, C } →
- 因为该 FD 中,BCE 涉及所有属性,只要一分解,这个 FD 必定消失
对 BCNF 的评价
- 最好的范式
- 避免重复和各种数据异常
- 给定一个 relation 实例,总能找到一个能满足 BCNF 的分解
- 可能会有 FD 丢失
BCNF 分解算法
每当我们找到一对违反 BCNF 的 schema R 及 FD:X → Y:
- 把 R 从 S 中删除
- 新建一个 schema 加入 S,其属性集为 R - Y
- 新建一个 schema 加入 S,其属性集为 X ∪ Y
- 例如:
![image]()
- 首先找出所有的候选键:AC
- 两个 FD 都违反 BCNF,其左侧都不是候选键
- 选择 { A } → { B, E }(也可选择 { C } → { D },最后分解不同)
- 根据规则,R 分解为 R1 = ( A, C, D ),R1 = ( A, B, E )
- 检查是否都满足 BCNF
![image]()
- 该过程是无损的吗?
- 是的
- 该过程是依赖保持的吗?
- 在这个例子中是的
检查一个 FD 是否违背 BCNF
- 检查 BCNF 只看 F 还是 需要看 F+?
- 检查 F 就够了,不需要去检查它的闭包 F+
- 例如:
- 不满足 BCNF,因为对于{ A } → { B } 和 { B } → { C },它们左侧属性都不是 key
- 我们不需要验证 F+,比如不需要检查隐含的FD:{ A } →
- 而对于一个分解,如果要检查分解的 schemas,则只看 F 是不够的
- 只检查 F ,会误判 R1 跟 R2 满足 BCNF
- 因此对于分解后的模式我们还需要考虑 F+ 中的FD
- 检查分解后的 Rn 是否满足 BCNF 的方法
- 例子:
![image]()
![image]()
关系模式规范化的目标
关系数据库设计的目标是
- BCNF
- 分解后没有信息丢失
- 依赖保持( 3NF:yes, BCNF:no )
如果不满足上述条件,我们可以采取
- 采取 BCNF,缺点:可能会丢失FD
- 采用 3NF,缺点:可能会存在冗余信息
ER 模型和规范化
- 对于一个好的 E-R 图设计,一般来说其产生的 relation schema 是不需要规范化处理的
- 但是不好的设计就会产生不好的 schemas,就需要规范化处理
- 例子:
- 考虑 Loans ( branch-name, loan-number, amount, customer-id, customer-name )和 FDs
- { loan-number } → { branch-name, amount, customer-id }.
- { customer-id } → { customer-name }.
- 我们应用 BCNF 分解算法:
- Loan ( loan-number, branch-name, amount, customer-id )
- Customer ( customer-id, customer-name )
- 这个分解是符合 BCNF 的
- 考虑 Loans ( branch-name, loan-number, amount, customer-id, customer-name )和 FDs
其他设计问题
- 规范化并不能解决所有缺点
- 例如:如果不采用统一 schema:earnings( company-id, year, amount ),而是每年一个 schema
- earnings-2000, earnings-2001, earnings-2002, etc., 所有这些表都是 ( company-id, amount ).
- 上面的表都是符合 BCNF 的,但是不能在同一个表上对多个年份进行查询,且对新的一年,都需要建立新的一张表
- company-year ( company-id, earnings-2000, earnings-2001, earnings-2002 )
- 也是符合 BCNF 的,但是每年都要创建新的属性
- earnings-2000, earnings-2001, earnings-2002, etc., 所有这些表都是 ( company-id, amount ).








浙公网安备 33010602011771号