Skip to content

关系模式的分解

关系数据库理论 中我们看到:一张「什么都装」的大表会带来冗余和操作异常。模式分解就是把 \(R\) 拆成多个子模式 \(\rho = \{R_1,\ldots,R_k\}\),使每个子表职责更单一。分解要有标准,否则可能「拆坏了」。


规范化的直观目标

  • 基本思想一事一地——一个关系尽量只描述一个概念、实体或实体间的一种联系;不该放在一起的属性就分离出去。

  • 过程(实操时可循环):找候选码 → 列出函数依赖 → 若有决定因子不是候选码,把相关属性抽到新表,决定因子作新表的主码,在原表用外码引用 → 重复直到各表决定因子都是码级(或达到你选择的范式目标)。

Note

满足范式不是唯一真理;有时为查询性能会有意保留少量冗余,但要清楚代价。


分解希望同时满足的三件事

目标 含义(直观)
达到 3NF / BCNF 控制冗余与异常,依赖结构更干净
无损连接 拆开后做自然连接,能还原原来的信息,不增不减
保持函数依赖 原来 \(F\) 里的语义在分解后仍能被各子表上的依赖体现

实务权衡:尽量 BCNF;若 BCNF 分解会不能保持依赖,可降为 3NF,以求 无损 + 保持依赖

好设计的三个取向:表达性(无损、保持依赖)、分离性(按范式拆开)、最小冗余(表个数与总属性别无谓膨胀)——第三点要与查询频率权衡。


无损连接分解

定义:分解 \(\rho=\{R_1,\ldots,R_n\}\) 对关系 \(r\) 若满足

\[ r = \pi_{R_1}(r) \bowtie \pi_{R_2}(r) \bowtie \cdots \bowtie \pi_{R_n}(r) \]

(恒对任意合法 \(r\) 成立),则称 \(\rho\)\(F\) 上的无损分解

若连接后行数变多、出现原来没有的拼法,信息由确定变不确定,就是有损(课件中学号–课程–成绩错拆成「学号,课程号」与「学号,成绩」再连接会膨胀)。

两个子模式的快捷判定

\(\rho = \{R_1, R_2\}\)\(R\) 的分解,当且仅当下面至少一条\(F^+\) 蕴含时,分解无损

\[R_1 \cap R_2 \to R_1 - R_2 \quad\text{或}\quad R_1 \cap R_2 \to R_2 - R_1\]

即:公共属性能决定其中一侧「独有」的那部分属性。

多于两个子模式:Chase 表算法概述

  1. 建表:行对应 \(R_i\),列对应属性;若 \(A_j \in R_i\)\(a_j\),否则填 \(b_{ij}\)

  2. 对每个 \(X \to Y \in F\),若两行在 \(X\) 上符号相同而 \(Y\) 上不同,则按规则把 \(Y\) 上符号统一(优先改成下标更小的 \(a\))。

  3. 若某行出现\(a\)\(a_1,\ldots,a_n\)),则无损;否则有损


保持函数依赖的分解

  • 含义:把 \(F\) 投影到每个 \(R_i\)(只保留两端都在 \(R_i\) 中的依赖),得到 \(G = \bigcup_i \pi_{R_i}(F)\);若 \(G\) 逻辑蕴含 \(F\) 中每一条依赖,则称分解 保持依赖

Example

成绩(学号, 课程号, 教师 ID, 成绩),教师 ID→课程号。若只拆成 R1(学号,课程号,成绩) 与 R2(学号,教师 ID),则 教师 ID→课程号 无法在任何一张表内体现 → 不保持依赖

Tip

  • 保持依赖的分解 未必 无损;

  • 无损的分解 未必 保持依赖。

检验时:对 \(F\) 中每个 \(X \to Y\),在 \(G\) 上算 \(X^+_G\),看是否包含 \(Y\)(算法细节见教材)。

Example

\(R(C,S,Z)\)\(F=\{CS\to Z,\ Z\to C\}\)\(\rho=\{SZ,\ CZ\}\) 可无损,但 不保持 \(CS\to Z\)(需自行推导验证)。


分解到 3NF 的示例(保持依赖思路)

Example

  1. \(R(A,B,C,D,E,F,G)\)\(F=\{A\to B,\ A\to C,\ C\to D,\ C\to E,\ E\to FG\}\)

    候选码为 \(A\);有传递链 \(A\to C\to \cdots\),故不满 3NF

    常做法:把每个 FD 右部已单属性化后,每个依赖对应一张表(再合并左部相同的),例如:

    \[ R_{12}(A,B,C), R_{34}(C,D,E), R_5(E,F,G) \]

    使各表属 3NF 且常可做到 保持依赖(是否无损需按算法验证)。

  2. \(U=\{C,T,H,R,S,G\}\)\(F=\{CS\to G,\ C\to T,\ TH\to R,\ HR\to C,\ HS\to R\}\)

    \[ \rho=\{CSG,\ CT,\ THR,\ HRC,\ HSR\} \]

    即按依赖拆开后保持依赖的 3NF 分解之一。


Abstract

  • 为什么拆:减冗余、消插入/删除/更新异常。

  • 拆成什么样:优先 BCNF;必要时用 3NF保持依赖

  • 拆得对不对:用 无损保持依赖 两套标准分别检查。