# 规范化

> 计算机科学 · CIE A-Level
> 来源: https://www.owlsprep.com/zh/study/cie-9618-u8-normalisation/

本模块逐步讲解数据库规范化，从识别数据异常到将未规范化数据转换为1NF、2NF、3NF和BCNF。它还涵盖了实际数据库设计中反规范化的有意权衡，完全符合CIE A-Level 9618的要求。

**先修:** [关系数据库概念，主键和外键](https://www.owlsprep.com/zh/study/cie-9618-u8-relational-model/)

## 学习目标

- 解释规范化的目的，列举常见的数据异常
- 逐步将未规范化数据转换为1NF、2NF和3NF
- 理解BCNF的定义和要求
- 评估实际数据库设计中反规范化的权衡

## 规范化的目的与数据异常

规范化是在关系数据库中组织数据的系统化过程，目的是减少冗余数据存储，消除不良的数据异常。它将大型非结构化表拆分为更小、连接良好的表，保持数据一致性。

**数据异常** — 插入、更新或删除记录时，因冗余数据产生的意外不一致。主要有三种类型：插入异常、删除异常和更新异常。

*例:* 将学生姓名和课程细节存储在同一个表中，会导致学生姓名在多个课程中重复存储。

- - **更新异常**：修改学生姓名需要更新该学生的每一行，如果遗漏某一行就会导致不一致。
- - **插入异常**：在至少有一个学生选修该课程之前，你无法向数据库添加新课程。
- - **删除异常**：删除某课程的最后一个注册学生时，会意外删除该课程本身的所有记录。

**例题:** 识别以下场景中的异常类型：一个表存储 `(OrderID, CustomerID, CustomerName, CustomerAddress, ProductID, ProductName)`。如果某个客户的所有订单都被删除，该客户的联系信息也会丢失。命名异常并解释其发生原因。

1. 这是删除异常，由客户数据的冗余存储导致。
2. 客户详情函数依赖于CustomerID（客户的唯一标识符），而非OrderID（订单的唯一标识符）。这意味着同一客户的每个订单都会重复存储客户数据。
3. 当某个客户的所有订单都被删除后，表中不再有包含该客户详情的行，因此数据被意外丢失。

> **考试提示:** CIE考官通常会要求你在给定场景中命名并解释异常，而不只是回忆定义。一定要将异常与冗余数据存储联系起来。

## 第一范式和第二范式

规范化是逐步应用的，每个范式都比前一个增加了更严格的规则。大多数CIE考题要求规范化到3NF，因此按步骤顺序操作非常重要。

**第一范式 (1NF)** — 如果关系的所有属性都只包含原子（不可分割）值，且不存在重复数据组，则该关系符合1NF。

*例:* 在学生的单个单元格中存储多个电话号码的表不符合1NF。

**第二范式 (2NF)** — 如果关系符合1NF，且所有非键属性都完全函数依赖于整个主键（不存在部分依赖），则该关系符合2NF。2NF仅适用于具有复合主键的关系。

*例:* 如果主键是 `(StudentID, CourseID)`，`StudentName` 仅依赖于 `StudentID`（主键的一部分），这就是违反2NF的部分依赖。

**例题:** 将以下未规范化关系转换为1NF，再转换为2NF：一个学生可以选修多门课程。未规范化关系：`Student(StudentID, StudentName, StudentEmail, CourseID, CourseName)`。

1. 首先，分解每个学生的重复课程数据组，得到带有复合主键的1NF：
2. $$\text{Student_1NF (StudentID, StudentName, StudentEmail, CourseID, CourseName)}$$
3. 接下来，识别部分依赖：`StudentName, StudentEmail` 仅依赖于 `StudentID`，`CourseName` 仅依赖于 `CourseID`。两者都是对复合主键 `(StudentID, CourseID)` 的部分依赖。
4. 拆分出三个关系消除部分依赖，得到2NF：
5. $$\begin{aligned} \text{Student (StudentID, StudentName, StudentEmail)} \\ \text{Course (CourseID, CourseName)} \\ \text{Enrolment (StudentID, CourseID)} \end{aligned}$$

**概念自测**

检查你对2NF规则的理解：

1. 以下关于2NF的陈述哪一个是正确的？

   - 2NF适用于所有关系，无论主键类型是什么
   - 单属性主键的关系自动符合2NF
   - 2NF消除传递依赖
   - 2NF允许重复组

   *答案:* 单属性主键的关系自动符合2NF

   *解析:* 正确。部分依赖仅在主键是复合主键时存在，因此单属性主键意味着所有非键属性都完全依赖于整个主键。

## 第三范式和BCNF

完成2NF后，下一步是3NF，这是CIE考试中规范化最常要求的最终目标。博伊斯-科德范式（BCNF）是3NF的更严格扩展，用于处理更复杂的依赖情况。

**第三范式 (3NF)** — 如果关系符合2NF，且没有非键属性传递依赖于主键，则该关系符合3NF。所有非键属性必须仅依赖于主键，不能依赖于其他非键属性。

**博伊斯-科德范式 (BCNF)** — 如果关系符合3NF，且对于每个非平凡函数依赖 $X \rightarrow Y$，$X$ 都是该关系的超键，则该关系符合BCNF。它解决了非键属性决定主键一部分的依赖问题。

**例题:** 将以下2NF关系转换为3NF：`Course(CourseID, CourseName, TutorID, TutorName, Department)`。主键 = `CourseID`。

1. 首先，识别函数依赖：`TutorID \rightarrow TutorName, Department`。这是传递依赖，因为`TutorID`是依赖于主键`CourseID`的非键属性，因此`TutorName`和`Department`通过`TutorID`依赖于`CourseID`。
2. 拆分出两个关系消除传递依赖，得到3NF：
3. $$\begin{aligned} \text{Course (CourseID, CourseName, TutorID)} \\ \text{Tutor (TutorID, TutorName, Department)} \end{aligned}$$
4. 检查BCNF：每个函数依赖的左侧都是超键，因此两个关系也都符合BCNF。

> **考试提示:** 除非题目明确要求BCNF，否则停止在3NF即可。额外工作不会扣分，但会浪费宝贵的考试时间。

## 反规范化：权衡

规范化并不总是最优的最终数据库设计。反规范化是在已规范化数据库中有意引入冗余以提升性能的操作。

**反规范化** — 将更高范式的关系合并的过程，目的是减少常见查询所需的连接次数，代价是增加冗余，提高异常风险。

- - **优势**：读查询更快，因为检索常用数据所需的连接次数更少
- - **常见用例**：数据仓库、报表系统和读密集型应用
- - **代价**：更高的存储需求，更新时避免数据不一致的逻辑更复杂

**例题:** 举一个设计师会选择对3NF数据库进行反规范化的例子。

1. 电商网站在客户订单历史中，每条订单都会显示商品名称，会选择反规范化来提升性能。
2. 规范化设计每次加载订单历史都需要将`Order`表和`Product`表连接，这是一个高频操作。
3. 将商品名称直接存储在`Order`表中消除了连接需求，加快了终端用户的查询响应速度，尽管商品名称被冗余存储。

## 常见错误

- **错误做法:** 要求规范化到3NF时停止在1NF或2NF，未解决依赖问题
  - 原因: 很多考生忘记规范化是增量过程，每个范式都要求首先满足更低范式的所有规则
  - 正确做法: 始终按顺序操作：1NF → 2NF → 3NF，进入下一步前检查每个规则
- **错误做法:** 解释时混淆部分依赖（2NF）和传递依赖（3NF）
  - 原因: 考生经常混淆违反不同范式的两种依赖类型的定义
  - 正确做法: 记住：部分依赖 = 非键依赖于复合主键的一部分（2NF规则）；传递依赖 = 非键依赖于另一个非键（3NF规则）
- **错误做法:** 在一个单元格中保留多个值仍称其符合1NF，违反原子性要求
  - 原因: 考生有时会赶时间，忘记1NF的核心规则是所有属性必须是原子的
  - 正确做法: 拆分重复组为单独的行或单独的关系，确保1NF中每个单元格只存储一个值
- **错误做法:** 声称反规范化始终是不良实践，绝不应该使用
  - 原因: 规范化旨在减少异常，但它不是所有用例的最优选择
  - 正确做法: 将反规范化视为读密集型系统的有意设计选择，其性能提升超过冗余的代价

## 速查表

| 范式 | 核心要求 |
| --- | --- |
| 未规范化 | 包含重复组或非原子值 |
| 1NF | 所有属性原子；无重复组 |
| 2NF | 1NF + 无部分依赖（非键依赖于整个主键） |
| 3NF | 2NF + 无传递依赖（非键仅依赖于主键） |
| BCNF | 3NF + 每个函数依赖的决定因素都是超键 |

## 下一步

规范化是关系数据库的核心设计技能，建立在关系模型基础概念之上。掌握它可以确保你设计出一致、高效的数据库，避免冗余存储导致的常见数据异常。它是CIE A-Level 9618 试卷2中频繁考察的主题，因此练习将未规范化关系转换为3NF，提升考试速度非常重要。接下来，你可以继续学习如何用SQL实现规范化数据库设计，探索事务处理和并发控制，或是学习完整A-Level大纲中的高级数据库概念。

- [客户-服务器与分布式数据库](https://www.owlsprep.com/zh/study/cie-9618-u8-client-server-and-distributed-databases/)
- [事务与并发控制](https://www.owlsprep.com/zh/study/cie-9618-u8-transactions-and-concurrency-control/)
- [算法设计与问题求解](https://www.owlsprep.com/zh/study/cie-9618-u9-overview/)

---

来自 [OwlsPrep](https://www.owlsprep.com) —— A-Level / IB / AP / IGCSE 免费学习指南，依据官方考纲编写。原页面：https://www.owlsprep.com/zh/study/cie-9618-u8-normalisation/
