表怎么拆:拆不好有冗余与更新异常,拆过头全是连接。用函数依赖 + 范式给出「拆到哪」的判据。
函数依赖(FD): 表示「两个元组在 X 上相等,则在 Y 上也相等」——X 唯一决定 Y。
学号 → 姓名 (知道学号,姓名唯一确定)
学号, 课程号 → 成绩
系 → 系主任 (一个系一个主任)
函数依赖不是「某时刻碰巧唯一」,而是业务规则上恒成立的决定关系,是规范化的原材料。
候选码 = 能函数决定全部分量、且任何真子集都不行的属性组。
闭包 :从 X 出发、用全部 FD 反复推导出的属性集合:
X⁺ = X
重复:若存在 Y→Z 且 Y ⊆ X⁺,则 X⁺ = X⁺ ∪ Z
直到 X⁺ 不再变化
是候选码 覆盖所有属性、且 X 最小。闭包是判断「是否码、依赖是否蕴含」的机械手段。
1NF ──消除部分依赖──▶ 2NF ──消除传递依赖──▶ 3NF ──消除主属性对码的部分/传递──▶ BCNF
| 范式 | 要消除的异常 | 典型问题 |
|---|---|---|
| 1NF | 属性不可再分(原子性) | 一个字段塞多个值(如「多门课」) |
| 2NF | 非主属性对码的部分依赖 | 学号+课程号 → 姓名(姓名只依赖学号) |
| 3NF | 非主属性对码的传递依赖 | 学号 → 系 → 系主任 |
| BCNF | 主属性对码的部分/传递依赖 | 每个决定因素都是码 |
例:选课(学号, 课程号, 姓名, 系, 系主任, 成绩)
学生(学号,姓名,系,系主任) 和 选课(学号,课程号,成绩)。学生 表传递依赖 学号→系→系主任 → 违反 3NF,再拆出 系(系,系主任)。规范化 = 无损分解:拆成更高范式的关系,且能靠自然连接无损还原。套路:先 1NF,再逐级消部分、消传递。
范式不是越高越好:过度拆分使每次查询多表连接(第 4 章),性能下降。
对比:规范化 vs 反规范化——规范化追求零冗余零异常,适合写密集 OLTP(订单、账户),代价是查询连接多、读变慢;反规范化故意保留冗余(订单里冗余存「商品名」)换读性能,适合读密集 OLAP(报表、数仓)。现实常在 3NF 上做局部反规范化,用应用层/触发器保证冗余不漂移。还牵涉索引(第 9 章)与 NoSQL(第 10 章)。