数据规范化
规范化数据库的样式以及表结构为何重要。
数据规范化是在数据库中组织信息的过程,旨在减少冗余并提高数据库效率。可以将规范化理解为一种确保数据库中每个字段和表逻辑组织的方式,从而避免在数据异常插入、更新或删除记录时出现。此过程根据特定的规则执行,这些规则规定了表的组织方式。
规范化是更大数据清洗和标准化过程的一部分,其中还包括确认您的数据准确、完整且不包含重复记录,并确保您为字段选择了适当的数据类型。如果您从非规范化表开始,规范化过程将涉及创建额外的、更小的表,这些表可以通过外键相互联接。也许您曾因单个值更改后必须在数据库中的多个位置更新相同信息而感到沮丧,或者发现当记录被删除时会丢失有价值的数据。对表进行规范化将有助于解决这两种情况。
本课程中涵盖的原则适用于关系数据库管理系统 (RDBMS)。如果您使用的是 NoSQL 或基于文档的数据库(例如 MongoDB),则以下信息不适用。
简化和减少存储:规范化数据的好处
规范化旨在提高数据效率,以便您的团队能够查找和使用所需信息。一旦您熟悉数据库的工作方式,这些好处和规则可能看起来是常识,但了解数据库中每个表和字段的明确目的非常有益。规范化数据的好处包括:
-
简化事务查询。使用规范化数据,客户地址查询只需在存储这些地址的单个字段中查找。如果您在数据库的不同位置多次存储客户地址,甚至在同一字段中保留多个地址,则该查询将需要更长时间才能执行。
-
减小数据库大小。如果您在数据库中的多个位置重复客户数据,这意味着您已为存储该信息多次腾出空间。如果您的数据库只包含少量表,这可能不是主要问题,但如果您的规模较大,磁盘空间可能会非常宝贵。减少重复信息意味着降低存储成本,无论您是运行本地服务器还是依赖云托管数据库。
-
简化数据库维护。想想同一客户数据在数据库中存储了多次。每次客户更改地址时,
Customer Address
字段的每个实例都需要更新,这会留下大量出错空间。如果您的数据经过规范化,您将只有一个Customer Address
字段,该字段联接到其他相关表,例如Orders
。
数据异常
数据异常是数据库中信息存储方式的不一致性。当记录更新、添加或删除时出现问题时,这些数据库结构缺陷就会显现出来。幸运的是,遵循规范化规则可以从一开始就防止这些异常的发生。
更新异常
更新异常源于数据冗余。例如,假设您的数据库在多个表中存储客户地址信息。客户更改地址可能只导致其中一个字段更新以包含新信息,从而导致数据不一致。
插入异常
**插入异常**发生于在某些字段不包含数据(可能尚未存在的数据)的情况下无法创建记录时。例如,非规范化数据库的结构可能导致除非客户下过订单,否则无法创建客户帐户。对该数据库进行规范化将通过创建独立的Orders
和Customers
表来解决此问题,并且没有禁止空值的规则。
删除异常
意外信息丢失是**删除异常**的结果。假设您的数据库中的一个表包含有关大学课程和选修这些课程的学生的信息。如果某个课程因选课人数不足而被取消,您可能会在删除该课程记录时意外丢失有价值的学生信息。与插入异常一样,将数据拆分成多个特定表将防止此问题。
规范化规则
数据规范化规则于 20 世纪 70 年代初首次引入。这些规则分为称为范式的层级。每个层级都建立在前一个层级之上——只有当您的数据已经满足第一个层级的规则时,您才能应用第二个层级的规则,依此类推。尽管除了下面列出的三个范式之外还有更多范式,但前三个对于大多数用例来说已足够。
正如我们在数据库简介中介绍的,数据库中的表应包含一个实体键,也称为主键。此字段根据唯一 ID 区分表中的每一行,在联接表时很有用。在我们甚至进入第一范式之前,您的表需要有一个实体键字段。
第一范式 (1NF)
**第一范式** (1NF) 规定表中的每个字段应仅存储一个值,并且您的表不应包含存储相似信息的多个字段,例如名为 Address1 和 Address2 的列。
以下是一个我们将根据第一范式进行规范化的表示例。此表包含大学课程及其授课教师的信息。
教授表
教授 ID | 教授姓名 | 课程名称 |
---|---|---|
P001 | Gene Watson | 哲学导论;伦理学 |
P002 | Melissa King | 量子力学 |
P003 | Errol Tyson | 宏观经济学 |
P004 | Mary Jacobson | 图画小说 |
我们注意到,虽然我们的字段是独立的,但一位教授(第一行中的 Gene Watson)正在教授两门课程,并且该信息当前存储在单个单元格中。如果根据 1NF 对此表进行规范化,我们需要将数据拆分成多个表:
规范化教授表
教授 ID | 教授姓名 |
---|---|
P001 | Gene Watson |
P002 | Melissa King |
P003 | Errol Tyson |
P004 | Mary Jacobson |
规范化课程表
课程 ID | 课程名称 | 教授 ID |
---|---|---|
C001 | 哲学导论 | P001 |
C002 | 伦理学 | P001 |
C003 | 量子力学 | P002 |
C004 | 宏观经济学 | P003 |
C005 | 图画小说 | P004 |
由于一位教授可以教授多门课程,我们已将此数据拆分成两个表。现在,我们的Professor
表与Course
表具有一对多关系。这种新的表结构满足第一范式,并通过外键Professor ID
字段联接两个表。
第二范式 (2NF)
**第二范式**旨在减少冗余并确保每个字段都描述实体键标识的内容。要满足 2NF,表中所有非实体键字段必须完全依赖于表的实体键(实体键可以是两个字段组成的复合键)。我们来看一个新示例——一个包含员工生日信息的表。
员工生日表
员工 ID | 生日 | 部门 |
---|---|---|
E001 | 11 月 18 日 | 会计 |
E002 | 3 月 29 日 | 销售 |
E003 | 6 月 1 日 | 市场营销 |
E004 | 2 月 7 日 | 会计 |
此表满足 1NF,因为每列都是独立的,并且每个单元格中只包含一个值。但是,此表有一个复合键:Employee ID
+ Birthday
组合构成了表的实体键。此表目前不满足 2NF,因为Department
字段仅部分依赖于复合键,因为员工的部门不依赖于他们的生日,而只依赖于他们的员工 ID。为了解决这个问题,我们将把这些信息拆分成两个表:
规范化员工生日表
员工 ID | 生日 |
---|---|
E001 | 11 月 18 日 |
E002 | 3 月 29 日 |
E003 | 6 月 1 日 |
E004 | 2 月 7 日 |
规范化员工部门表
员工 ID | 部门 |
---|---|
E001 | 会计 |
E002 | 销售 |
E003 | 市场营销 |
E004 | 会计 |
第三范式 (3NF)
如果一个表(除了满足 2NF 之外)不包含任何传递依赖,则该表满足**第三范式**。当列 A 依赖于列 B,而列 B 又依赖于实体键时,就会发生传递依赖。如果您想根据 3NF 进行规范化,您需要从表中移除列 A,因为它不直接依赖于实体键,并将其放置在具有其自身实体键的不同表中。
订单表
订单 ID | 订单日期 | 客户 ID | 客户邮政编码 |
---|---|---|---|
R001 | 01/17/2021 | C032 | 99702 |
R002 | 03/01/2021 | C004 | 39204 |
R003 | 06/30/2021 | C054 | 06505 |
R004 | 08/22/2021 | C010 | 84098 |
R005 | 09/27/2021 | C004 | 39204 |
此表不符合第三范式,因为Customer zip code
字段依赖于Customer ID
,而Customer ID
不是此表的实体键(此处的实体键是Order ID
)。我们当前的结构可能导致意外的信息丢失;如果客户 C032 退回了订单,我们需要删除此记录,我们可能会意外丢失其邮政编码信息。如果客户 C004 搬家且其邮政编码发生变化,我们也必须在两个地方更新它,因为他们下过多个订单。为了使此表符合 3NF——您猜对了——我们将把它拆分成两个表。
规范化订单表
订单 ID | 订单日期 | 客户 ID |
---|---|---|
R001 | 01/17/2021 | C032 |
R002 | 03/01/2021 | C004 |
R003 | 06/30/2021 | C054 |
R004 | 08/22/2021 | C010 |
R005 | 09/27/2021 | C004 |
规范化客户表
客户 ID | 客户邮政编码 |
---|---|
C032 | 99702 |
C004 | 39204 |
C054 | 06505 |
C010 | 84098 |
规范化的缺点:何时进行反规范化
一旦达到更高程度的规范化,您的数据库执行某些分析查询的速度可能会变慢——特别是那些需要获取大量数据的查询。由于规范化数据要求数据库访问多个表来执行查询,这可能需要更长时间,尤其是在您的数据库复杂性增加时。权衡之处在于,您的规范化数据占用空间更少。
下一步:什么是数据库视图?
什么是数据库视图,以及如何使用它来简化查询