数据规范化
规范化数据库的结构及其原因。
“数据规范化”是数据库中信息结构化的过程,旨在减少冗余并提高数据库效率。您可以将规范化视为一种确保数据库中每个字段和表都逻辑组织的方式,从而在插入、更新或删除记录时避免数据异常。这个过程是根据规定表应如何组织的特定规则执行的。
规范化是更广泛的数据清洗和标准化过程的一部分,该过程还包括确认您的数据准确、完整且不包含重复记录,以及确保您为字段选择了适当的数据类型。如果您从非规范化表开始,规范化过程将涉及创建额外的、较小的表,这些表可以通过外键相互连接。也许您曾因为单个值更改后不得不在数据库中多个位置更新相同信息而感到沮丧,或者发现删除记录时丢失了宝贵的数据。规范化您的表将在这两种情况下都有帮助。
本课程将介绍的原则适用于关系数据库管理系统(RDBMS)。如果您使用的是 NoSQL 或基于文档的数据库(如 MongoDB),则以下信息不适用。
简化和减少存储:规范化数据的好处
规范化的核心是提高数据效率,以便您的团队能够找到并使用所需的信息。一旦您对数据库的工作方式有所了解,这些好处和规则可能看起来是常识,但了解数据库中每个表和字段的明确目的非常有益。规范化数据的好处包括:
-
简化事务查询。对于规范化数据,查询客户地址只需查看存储这些地址的单个字段。如果您在数据库中不同位置多次存储客户地址,甚至在同一字段中保留多个地址,则该查询执行时间会更长。
-
减少数据库大小。如果您在数据库中多个位置重复客户数据,这意味着您为存储这些信息预留了多份空间。如果您的数据库只包含几个表,这可能不是主要问题,但如果您的工作规模较大,磁盘空间可能会非常宝贵。减少重复信息意味着降低存储成本,无论您是运行本地服务器还是依赖云托管数据库。
-
简化数据库维护。考虑同一客户数据在数据库中存储多次的情况。每次客户更改地址时,都需要在每个`Customer Address`字段实例中进行更新,这会留下大量出错的可能性。如果您的数据是规范化的,则只有一个`Customer Address`字段,该字段连接到其他相关表,如`Orders`。
数据异常
数据异常是指信息在数据库中存储方式的不一致。当记录更新、添加或删除时出现问题时,数据库结构中的这些缺陷就会显现出来。幸运的是,遵循规范化规则可以从一开始就防止这些异常的发生。
更新异常
更新异常源于数据冗余。例如,假设您的数据库在多个表的字段中存储客户地址信息。客户更改地址可能只会导致其中一个字段更新以包含新信息,从而导致数据不一致。
插入异常
当没有某些字段包含数据(这些数据可能尚不存在)就无法创建记录时,就会发生**插入异常**。例如,非规范化数据库的结构可能导致除非客户下订单,否则无法创建客户账户。通过创建单独的 `Orders` 和 `Customers` 表,且没有禁止空值的规则,规范化该数据库将解决此问题。
删除异常
**删除异常**会导致意外的信息丢失。假设您的数据库中的一个表包含大学课程和选修这些课程的学生信息。如果一门课程因选课人数不足而被取消,您可能会在删除该课程记录时无意中丢失宝贵的学生信息。与插入异常一样,将数据分解为多个特定表将防止此问题。
规范化规则
数据规范化的规则于 20 世纪 70 年代初首次提出。这些规则分为不同的层级,称为“范式”。每个层级都建立在前一个层级之上——只有当您的数据已经满足第一个层级的规则时,才能应用第二个层级的规则,依此类推。尽管除了下面列出的三个范式之外还有更多的范式,但这前三个范式足以满足大多数用例。
正如我们在数据库简介中介绍的,数据库中的表应包含一个实体键,也称为主键。此字段根据唯一 ID 区分表中的每一行,在连接表时非常有用。在我们甚至进入第一范式之前,您的表就需要有一个实体键字段。
第一范式(1NF)
第一范式(1NF)规定表中的每个字段只能存储一个值,并且您的表不应包含存储相似信息的多个字段,例如标题为**地址 1** 和**地址 2** 的列。
这是一个我们将根据第一范式进行规范化的表示例。此表包含有关大学课程及其授课者信息。
教授表
教授 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 |
这个表不符合第三范式,因为`客户邮政编码`字段依赖于`客户 ID`,而`客户 ID`不是这个表的实体键(这里的实体键是`订单 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 |
规范化的缺点:何时反规范化
一旦达到更高的规范化级别,您的数据库执行某些分析查询的速度可能会变慢——特别是那些需要获取大量数据的查询。由于规范化数据要求数据库查询多个表来执行查询,这可能需要更长的时间,尤其是在您的数据库变得复杂时。其权衡是规范化数据占用更少的空间。