关系型数据库设计的规范化与优化
立即解锁
发布时间: 2025-08-23 00:28:03 阅读量: 5 订阅数: 11 


数据库系统概念与应用
### 关系型数据库设计:从基础到高级范式
#### 1. 数据库设计基础与第一范式
数据库设计的核心目标是创建一组关系模式,以无冗余地存储信息,同时方便信息的检索。第一范式(1FN)是关系设计的基本要求,它规定关系中所有属性的域必须是原子的。简单来说,原子域的元素是不可分割的单位。
例如,若员工关系模式包含“子女”属性,其域为姓名集合,那么该模式就不符合第一范式,因为姓名集合不是原子的。同样,像“地址”这种复合属性,包含“街道”和“城市”等组件,其域也不是原子的。
整数通常被认为是原子的,所以整数集合是原子域,但所有整数集合的集合则不是原子域。不过,关键不在于域本身,而在于域元素在数据库中的使用方式。如果将每个整数视为有序的数字列表,那么所有整数的域就不是原子的。
使用非原子属性可能导致数据冗余和不一致。以账户和客户关系为例,如果数据库设计者将每个账户的一组持有人和每个客户的一组账户存储起来,那么每次创建账户或更新账户持有人集合时,都需要在两个地方进行更新,否则数据库可能会处于不一致状态。若只保留其中一个集合,虽然可以避免信息重复,但会使一些查询变得复杂。
#### 2. 关系型数据库设计的难点
在设计关系型数据库时,可能会遇到一些问题,主要包括信息重复和某些信息无法直接表示。以银行贷款为例,若将贷款信息存储在一个名为“empréstito”的关系中,其模式为(分行名称,分行城市,资产,客户姓名,贷款编号,贷款金额)。当添加新贷款时,需要重复分行的资产和城市数据。而且,若分行资产发生变化,需要修改多个元组,这不仅浪费空间,还增加了数据库更新的复杂性。
此外,该设计无法直接表示每个分行的信息,除非该分行至少有一笔贷款。解决这个问题可以引入空值,但空值处理起来比较困难。若不使用空值,只能在分行产生第一笔贷款申请后创建分行信息,并在所有贷款还清后删除该信息,这显然不是理想的设计。
#### 3. 函数依赖的概念与应用
函数依赖在区分数据库的好坏设计中起着关键作用,它是对键概念的一种推广。对于关系模式R,若在任何合法关系r(R)中,对于所有满足t1 [α] = t2 [α]的元组对t1和t2,都有t1 [β] = t2 [β],则称函数依赖α →β在模式R中成立。
例如,在“info - préstamo”模式(贷款编号,分行名称,客户姓名,贷款金额)中,预期成立的函数依赖有“贷款编号 →贷款金额”和“贷款编号 →分行名称”,但不期望“贷款编号 →客户姓名”成立,因为一笔贷款可能授予多个客户。
函数依赖有两个主要用途:一是验证关系是否合法,若关系r满足一组函数依赖F,则称r满足F;二是指定合法关系集合的约束,若希望将关系限制为满足F的模式R的关系,则称F在R中成立。
函数依赖还可分为平凡和非平凡的。像A →A和AB →A这种依赖,所有涉及该属性的关系都满足,它们是平凡的函数依赖。一般来说,若β ⊆α,则α →β是平凡的。
#### 4. 函数依赖的闭包与推理规则
给定一组函数依赖F,其闭包F+是由F逻辑蕴含的所有函数依赖的集合。计算F+可以直接根据函数依赖的定义进行,但如果F很大,这个过程会很漫长且困难。
为了简化推理过程,有一组称为阿姆斯特朗公理的规则:
- 自反律:若α是一组属性且β ⊆α,则α →β成立。
- 增广律:若α →β成立,且γ是一组属性,则γα →γβ成立。
- 传递律:若α →β成立且β →γ成立,则α →γ成立。
阿姆斯特朗公理是正确且完备的。此外,还有一些额外的规则可以通过阿姆斯特朗公理证明其正确性:
- 合并律:若α →β和α →γ成立,则α →βγ成立。
- 分解律:若α →βγ成立,则α →β和α →γ成立。
- 伪传递律:若α →β和γβ →δ成立,则αγ →δ成立。
例如,对于模式R = (A, B, C, G, H, I)和函数依赖集合F = {A →B, A →C, CG →H, CG →I, B →H},可以通过这些规则推出F+中的一些成员,如A →H、CG →HI和AG →I等。
#### 5. 属性集的闭包及其应用
为了检查一个属性集α是否为超键,需要计算由α函数确定的属性集。一种有效的方法是计算α在函数依赖集合F下的闭包α+。计算α+的算法如下:
```plaintext
resultado := α;
while (cambios en resultado) do
for each dependencia funcional β →γ in F do
begin
if β ⊆resultado then resultado := resultado ∪γ;
end
```
属性集闭包的计算有多个用途:
- 检查α是否为超键:计算α+,并检查它是否包含R的所有属性。
- 检查函数依赖α →β是否成立:计算α+,并检查β是否是α+的子集。
- 提供计算F+的另一种方法:对于每个γ ⊆R,找到γ+,并为每个S ⊆γ+生成函数依赖γ →S。
#### 6. 正则覆盖
为了减少检查函数依赖违反情况的工作量,可以使用与给定函数依赖集合F具有相同闭包的简化集合。正则覆盖Fc就是这样一个集合,它具有以下特性:
- Fc中的任何函数依赖都不包含稀有属性。稀有属性是指可以在不改变函数依赖集合闭包的情况下删除的属性。
- Fc中每个函数依赖的左侧是唯一的。
计算正则覆盖的过程如下:
```plaintext
Fc = F
repeat
使用合并律将Fc中形式为α1 →β1和α1 →β2的依赖替换为α1 →β1 β2。
找到Fc中具有稀有属性的函数依赖α →β。
如果找到稀有属性,从α →β中删除它。
until Fc不再改变。
```
正则覆盖Fc与F具有相同的闭包,因此检查Fc是否满足等同于检查F是否满足。而且,Fc在某种意义上是最小的,它不包含稀有属性,并合并了左侧相同的函数依赖,因此检查Fc比检查F更经济。
#### 7. 关系分解
当关系模式包含过多属性时,需要将其分解为多个属性较少的模式。但不谨慎的分解可能会导致另一种不良设计。
例如,将“empréstito”模式分解为(分行名称,分行城市,资产,客户姓名)和(客户姓名,贷款编号,贷款金额)两个模式后,在某些情况下,当需要重建贷款关系时,可能会得到比原始关系更多的元组,导致信息丢失。这种分解被称为有损分解,而无损分解则不会丢失信息。
若两个模式R1和R2是R的分解,当且仅当至少满足以下函数依赖之一时,该分解是无损连接分解:
- R1 ∩R2 →R1
- R1 ∩R2 →R2
#### 8. 分解的理想属性
##### 8.1 无损连接分解
在将一个关系分解为多个较小关系时,无损连接分解至关重要。对于关系模式R和函数依赖集合F,若R1和R2是R的分解,且R1 ∩R2是R1或R2的超键,则该分解是无损连接分解。
以“empréstito”模式为例,将其分解为(分行名称,分行城市,资产)和(分行名称,客户姓名,贷款编号,贷款金额),由于“分行名称 →分行城市 资产”,根据增广律可知“分行名称 →分行名称 分行城市 资产”,且两个模式的交集为“分行名称”,所以该初始分解是无损连接分解。接着将(分行名称,客户姓名,贷款编号,贷款金额)分解为(贷款编号,分行名称,贷款金额)和(客户姓名,贷款编号),由于“贷款编号 →贷款金额 分行名称”,所以这个分解也是无损连接分解。
##### 8.2 依赖保持
数据库设计的另一个目标是保持函数依赖。当数据库进行更
0
0
复制全文
相关推荐










