本文介绍初学者的数据库规范化术语。 在讨论关系数据库设计时,基本了解此术语非常有用。
规范化说明
规范化是在数据库中组织数据的过程。 它包括根据旨在保护数据的规则在这些表之间创建表和建立关系,并通过消除冗余和不一致的依赖项使数据库更加灵活。
冗余数据会浪费磁盘空间并造成维护问题。 如果必须更改存在于多个位置的数据,则必须在所有位置以完全相同的方式更改数据。 如果数据仅存储在 Customers 表中,并且数据库中没有其他位置,则客户地址更改更易于实现。
什么是“不一致的依赖项”? 虽然用户在“客户”表中查找特定客户的地址是直观的,但在该表中查找负责该客户的员工的薪水就不太合理了。 员工的工资与员工相关或依赖于员工的表现,因此应移到“员工”表中。 不一致的依赖项可能会导致数据难以访问,因为查找数据的路径可能缺失或损坏。
数据库规范化有一些规则。 每个规则称为“普通形式”。如果观察到第一个规则,则表示数据库采用“第一个正常形式”。如果观察到前三个规则,则数据库被视为采用“第三种正常形式”。尽管有可能实现其他规范化级别,但第三种正常形式被视为大多数应用程序所需的最高级别。
与许多正式规则和规范一样,现实世界的方案并不总是允许完美的合规性。 通常,规范化需要额外的表格,一些客户认为这很繁琐。 如果决定违反规范化的前三个规则之一,请确保应用程序预测可能出现的任何问题,例如冗余数据和不一致的依赖项。
以下说明包括示例。
第一个普通形式
- 消除单个表中的重复组。
- 为每个相关数据集创建一个单独的表。
- 使用主键标识每组相关数据。
不要在单个表中使用多个字段来存储类似的数据。 例如,若要跟踪可能来自两个可能来源的清单项,库存记录可能包含供应商代码 1 和供应商代码 2 的字段。
添加第三个供应商时会发生什么情况? 添加字段不是解决方案;这需要程序和表格的修改,而且无法顺利适应供应商数量的动态变化。 相反,将所有供应商信息放在名为“供应商”的单独表中,然后将库存链接到具有项号键的供应商,或使用供应商代码密钥将库存链接到供应商。
第二种普通形式
- 为应用于多个记录的值集创建单独的表。
- 将这些表与外键关联。
记录不应依赖于除表的主键之外的任何内容(如果必要,可以使用复合键)。 例如,考虑会计系统中客户的地址。 客户表需要地址,但订单表、发货表、发票表、应收账款表和催收表也需要地址。 与其将客户的地址存储为每个表中的单独条目,不如将其存储在“客户”表或单独的“地址”表中的一个位置。
第三范式
- 消除不依赖于键的字段。
不属于该记录键的记录中的值不属于该表。 通常,只要一组字段的内容可以应用于表中的多个记录,请考虑将这些字段放在单独的表中。
例如,在员工招聘表中,可以包含候选人的大学名称和地址。 但你需要一份完整的大学列表进行分组邮件。 如果大学信息存储在考生表中,则无法列出没有当前候选人的大学。 创建单独的“大学”表,并将其链接到具有大学代码键的“候选人”表。
例外:坚持第三种正常形式,虽然理论上是可取的,但并不总是现实的。 如果你有“客户”表,并且想要消除所有可能的域间依赖项,则必须为城市、邮政编码、销售代表、客户类以及可能在多个记录中复制的任何其他因素创建单独的表。 从理论上讲,规范化值得追求。 但是,许多小型表可能会降低性能或超过打开的文件和内存容量。
仅对频繁更改的数据应用第三种正常形式可能更为可行。 如果某些依赖字段仍然存在,请设计应用程序,要求用户在更改任何字段时验证所有相关字段。
其他规范化形式
第四种普通形式,也称为 Boyce-Codd 普通形式(BCNF),第五种正常形式确实存在,但在实际设计中很少考虑。 忽略这些规则可能会导致数据库设计不完善,但不应影响功能。
规范化示例表
这些步骤演示了规范化虚构的学生表的过程。
非规范化表:
学生# 顾问 Adv-Room 类别1 第二类 Class3 1022 琼斯 412 101-07 143-01 159-02 4123 史密斯 216 101-07 143-01 179-04 第一个普通形式:无重复组
表应只有两个维度。 由于一名学生有多个课程,因此这些课程应列在单独的表中。 上述记录中的 Class1、Class2 和 Class3 表示设计问题。
电子表格通常使用第三维度,但表格不应该。 另一种看待此问题的方法是从一对多关系的角度出发,不要把一方和多方放在同一表中。 相反,应通过消除重复组(Class#),创建一个符合第一范式的表,如下示例所示:
学生# 顾问 Adv-Room 类# 1022 琼斯 412 101-07 1022 琼斯 412 143-01 1022 琼斯 412 159-02 4123 史密斯 216 101-07 4123 史密斯 216 143-01 4123 史密斯 216 179-04 第二种正常形式:消除冗余数据
请注意上表中每个 Student# 值的多个 Class# 值。 Class# 在功能上不依赖于 Student# (主键),因此这种关系不是第二种正常形式。
下列表格演示了第二范式:
学生:
学生# 顾问 Adv-Room 1022 琼斯 412 4123 史密斯 216 注册:
学生# 类# 1022 101-07 1022 143-01 1022 159-02 4123 101-07 4123 143-01 4123 179-04 第三种正常形式:消除不依赖于键的数据
在最后一个示例中,Adv-Room(顾问的办公室编号)在功能上依赖于顾问属性。 解决方案是将该属性从 Students 表移动到教职员工表,如下所示:
学生:
学生# 顾问 1022 琼斯 4123 史密斯 教职工
名称 房间 部门 琼斯 412 42 史密斯 216 42