数据库规范化(范式)
在本节中,你将学习数据库设计中的一个重要原则——规范化(Normalization)。我们将从“为什么需要规范化”开始,一步步了解不同的“范式”到底是什么,并通过简单的例子帮助你建立直观理解。
无论你将来使用哪种数据库系统,规范化都是帮助你建立结构清晰、逻辑合理、数据一致性高的数据库模型的关键技能。
为什么要规范化?
当你设计数据库表结构时,很容易就会遇到以下问题:
- 数据重复存储,占用空间;
- 数据不一致,比如一个地方更新了,另一个地方没变;
- 插入/删除/修改数据时容易出错;
- 表结构混乱,难以维护。
为了解决这些问题,就需要对数据表进行规范化处理,也就是按照“范式”的要求,把表拆分得更合理、字段安排得更清晰。
什么是范式(Normal Form)?
你可以把“范式”理解为一种设计标准,告诉你“怎样设计表结构才更好”。在数据库设计中,最常用的是前三种范式:
范式名称 | 简称 | 作用 |
---|---|---|
第一范式 | 1NF | 消除字段中的重复数据 |
第二范式 | 2NF | 消除字段对部分主键的依赖 |
第三范式 | 3NF | 消除字段对非主属性的传递依赖 |
下面我们一一讲解。
第一范式(1NF):字段不可再分
定义:每个字段必须是不可再分的原子值,不能是数组、列表、集合等结构。
例如,下面是一张不符合 1NF 范式的表:
学号 | 姓名 | 电话 |
---|---|---|
1001 | 小明 | 138xxx,139xxx |
你看,“电话”字段里存了两个号码,这是一列多值,违反了第一范式。
正确做法(1NF):可以将“电话”单独拆成一张表。
学生表:
学号 | 姓名 |
---|---|
1001 | 小明 |
电话表:
学号 | 电话 |
---|---|
1001 | 138xxx |
1001 | 139xxx |
第二范式(2NF):消除对主键的“部分依赖”
定义:在满足 1NF 的基础上,每个非主属性必须完全依赖于主键,不能只依赖主键的一部分。
适用于:主键是组合键时,要特别注意这个问题。
例如,下面是一张不符合 2NF 范式的表:
学号 | 课程名 | 成绩 | 姓名 |
---|---|---|---|
1001 | 数学 | 90 | 小明 |
1001 | 英语 | 85 | 小明 |
主键是(学号, 课程名),但是“姓名”只依赖于学号——这就是部分依赖。
正确做法(2NF):
学生表:
学号 | 姓名 |
---|---|
1001 | 小明 |
成绩表:
学号 | 课程名 | 成绩 |
---|---|---|
1001 | 数学 | 90 |
1001 | 英语 | 85 |
现在,“成绩”依赖的是(学号, 课程名),“姓名”依赖的是学号,表结构就更合理了。
第三范式(3NF):消除“传递依赖”
定义:在满足 2NF 的基础上,非主属性不能依赖于另一个非主属性。
换句话说,字段应该直接依赖主键,而不是间接依赖。
例如,下面是一张不符合 3NF 范式的表:
学号 | 姓名 | 班级ID | 班级名 |
---|---|---|---|
1001 | 小明 | 1 | 一班 |
这里,“班级名”依赖的是“班级ID”,“班级ID”依赖的是“学号”——形成了传递依赖。
正确做法(3NF):
学生表:
学号 | 姓名 | 班级ID |
---|---|---|
1001 | 小明 | 1 |
班级表:
班级ID | 班级名 |
---|---|
1 | 一班 |
现在,“班级名”归属于“班级”表,避免了传递依赖,结构更清晰。
小结
通过本节的学习,你应该掌握了以下关键点:
- 规范化的目的是减少冗余、提高数据一致性;
- 第一范式(1NF):字段必须是原子值,不能再拆;
- 第二范式(2NF):消除对主键的部分依赖;
- 第三范式(3NF):消除非主属性之间的传递依赖;
- 通过分表和设置主键/外键,可以达到范式要求。
当然,实际开发中,有时为了查询效率,会对范式适当“反规范化”处理(比如合并表结构)。但前提是你先懂得如何正确规范化,才能做出合理的设计选择。