第 5 章 · 关系数据库设计理论

表怎么拆:拆不好有冗余与更新异常,拆过头全是连接。用函数依赖 + 范式给出「拆到哪」的判据。

5.1 函数依赖:属性之间的决定关系

函数依赖(FD)XYX \to Y 表示「两个元组在 X 上相等,则在 Y 上也相等」——X 唯一决定 Y。

学号 → 姓名      (知道学号,姓名唯一确定)
学号, 课程号 → 成绩
系 → 系主任      (一个系一个主任)
  • 平凡依赖YXY \subseteq X(如 学号,姓名 → 学号),恒成立、无信息量。
  • 完全/部分依赖(学号,课程号)成绩(学号,课程号) \to 成绩 完全(缺一不可);(学号,课程号)姓名(学号,课程号) \to 姓名 部分(姓名只靠学号)。
  • 传递依赖学号系,系系主任学号 \to 系,系 \to 系主任,则 学号系主任学号 \to 系主任 传递。

函数依赖不是「某时刻碰巧唯一」,而是业务规则上恒成立的决定关系,是规范化的原材料。

5.2 码与闭包

候选码 = 能函数决定全部分量、且任何真子集都不行的属性组。

闭包 X+X^+:从 X 出发、用全部 FD 反复推导出的属性集合:

X⁺ = X
重复:若存在 Y→Z 且 Y ⊆ X⁺,则 X⁺ = X⁺ ∪ Z
直到 X⁺ 不再变化

XX 是候选码     \iff X+X^+ 覆盖所有属性、且 X 最小。闭包是判断「是否码、依赖是否蕴含」的机械手段。

5.3 范式:1NF → 2NF → 3NF → BCNF

1NF ──消除部分依赖──▶ 2NF ──消除传递依赖──▶ 3NF ──消除主属性对码的部分/传递──▶ BCNF
范式要消除的异常典型问题
1NF属性不可再分(原子性)一个字段塞多个值(如「多门课」)
2NF非主属性对码的部分依赖学号+课程号 → 姓名(姓名只依赖学号)
3NF非主属性对码的传递依赖学号 → 系 → 系主任
BCNF主属性对码的部分/传递依赖每个决定因素都是码

例:选课(学号, 课程号, 姓名, 系, 系主任, 成绩)

  • 部分依赖 (学号,课程号)姓名(学号,课程号)\to 姓名 → 违反 2NF,拆成 学生(学号,姓名,系,系主任)选课(学号,课程号,成绩)
  • 学生 表传递依赖 学号→系→系主任 → 违反 3NF,再拆出 系(系,系主任)

5.4 规范化步骤与反规范化

规范化 = 无损分解:拆成更高范式的关系,且能靠自然连接无损还原。套路:先 1NF,再逐级消部分、消传递。

范式不是越高越好:过度拆分使每次查询多表连接(第 4 章),性能下降。

对比:规范化 vs 反规范化——规范化追求零冗余零异常,适合写密集 OLTP(订单、账户),代价是查询连接多、读变慢;反规范化故意保留冗余(订单里冗余存「商品名」)换读性能,适合读密集 OLAP(报表、数仓)。现实常在 3NF 上做局部反规范化,用应用层/触发器保证冗余不漂移。还牵涉索引(第 9 章)与 NoSQL(第 10 章)。