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