数据库规范化基本信息的说明

本文向初学者介绍数据库规范化术语。 在讨论关系数据库的设计时,对这个术语有一个基本的了解是很有帮助的。

规范化说明

规范化是组织数据库数据的过程。 它包括创建表,并根据旨在保护数据的规则在这些表之间建立关系,并通过消除冗余和不一致的依赖项使数据库更加灵活。

冗余数据会浪费磁盘空间并产生维护问题。 在更改保存在多个位置的数据时,该数据必须在所有位置以完全相同的方式更改。 如果数据仅存储在 Customers 表中,而数据库中没有其他位置,则更容易实现客户地址更改。

什么是“不一致的依赖关系”? 虽然用户可以直观地在“客户”表中查看特定客户的地址,但查找该客户的员工的工资可能没有意义。 员工工资与员工相关,或取决于员工,因此应移至“员工”表。 不一致的依赖关系会使数据难以访问,因为查找数据的路径可能缺失或断开。

数据库规范化需要遵循一些规则。 每个规则称为“普通形式”。如果观察到第一个规则,则数据库将被视为“第一个正常形式”。如果观察到前三个规则,则认为数据库采用“第三种正常形式”。虽然其他规范化级别是可能的,但第三个正常形式被认为是大多数应用程序所需的最高级别。

与许多正式规则和规范一样,实际方案并不总是允许完全合规。 通常,规范化需要其他表,而一些客户认为这很麻烦。 如果决定违反前三个规范化规则,请确保应用程序能够处理可能出现的任何问题,如数据冗余和依赖关系不一致。

以下说明包括示例。

第一范式

  • 消除单个表中的重复组。
  • 为每组相关数据单独创建一个表。
  • 使用主键标识每组相关数据。

请勿在单个表中使用多个字段来存储类似数据。 例如,若要跟踪具备两个可能源头的库存商品,库存记录可能包含“供应商代码 1”和“供应商代码 2”的字段。

添加第三个供应商时会发生什么情况? 添加字段不是答案;它需要对程序和表进行修改,并且不能顺利地容纳动态数量的供应商。 正确的做法是,将所有供应商信息都单独存放在一个名为“供应商”的表中,然后使用一个商品编号键将库存链接到各供应商,或使用一个供应商代码键将各供应商链接到库存。

第二范式

  • 为应用于多条记录的值集创建单独的表。
  • 将这些表与外键关联。

如有必要,记录不应依赖于表的主键 (复合键以外的任何内容) 。 我们以会计系统中的客户地址为例来说明。 “客户”表需要地址,但是“订单”、“运输”、“发票”、“应收账款”和“收款”表也需要地址。 不要在每个表中分别存放客户地址条目,而是将其存储在一个地方,即存放在“客户”表或单独的“地址”表中。

第三范式

  • 消除不依赖于键的字段。

记录中不属于该记录键的值不属于表中。 通常,只要一组字段的内容可以应用于表中的多个记录,就应考虑将这些字段存放在单独的表中。

例如,一个“员工招募”表中可能包含求职者的大学名称和地址。 但是,你需要一个完整的大学列表来群发邮件。 如果大学信息存储在“求职者”表中,则无法在不提供当前求职者的情况下列出各所大学。 创建单独的“大学”表,并通过大学代码键将其链接到“求职者”表中。

异常:坚持第三种正常形式,虽然理论上是可取的,但并不总是可行的。 如果你有“客户”表,并且希望消除所有可能的字段间依赖关系,则必须为城市、邮政编码、销售代表、客户类以及可能在多个记录中重复的其他任何因素创建单独的表。 从理论上讲,规范化是值得追求的。 但是,许多小型表可能会降低性能或超过打开文件和内存容量。

将第三范式仅应用于频繁更改的数据可能更可行。 如果某些从属字段仍然存在,请将应用程序设计为要求用户在更改任何相关字段时验证所有相关字段。

其他规范化形式

第四正常形式,也称为 Boyce-Codd 正常形式 (BCNF) ,第五正常形式确实存在,但在实际设计中很少考虑。 忽略这些规则可能会导致数据库设计不够完美,但不应影响功能。

规范化示例表

这些步骤演示了规范化虚构学生表的过程。

  1. 非规范化表:

    学生编号 指导教师 咨询室 Class1 Class2 Class3
    1022 Jones 412 101-07 143-01 159-02
    4123 Smith 216 101-07 143-01 179-04
  2. 第一范式:无重复组

    表应只有两个维度。 由于一个学生有多个课程,因此这些课程应在单独的表中列出。 上述记录中的字段 Class1、Class2 和 Class3 指示存在设计问题。

    电子表格通常使用第三个维度,但表不应使用。 另一种看待这个问题的方法是使用一对多关系,不要将一方和多个方面放在同一个表中。 相反,通过消除重复组 (Class#) ,以第一个普通形式创建另一个表,如以下示例所示:

    学生编号 指导教师 咨询室 班级#
    1022 Jones 412 101-07
    1022 Jones 412 143-01
    1022 Jones 412 159-02
    4123 Smith 216 101-07
    4123 Smith 216 143-01
    4123 Smith 216 179-04
  3. 第二范式:消除冗余数据

    请注意上表中每个 Student# 值的多个 Class# 值。 Class# 在功能上不依赖于 Student# (主键) ,因此此关系不是第二个正常形式。

    下表演示了第二范式:

    学生:

    学生编号 指导教师 咨询室
    1022 Jones 412
    4123 Smith 216

    注册:

    学生编号 班级#
    1022 101-07
    1022 143-01
    1022 159-02
    4123 101-07
    4123 143-01
    4123 179-04
  4. 第三范式:消除与键无关的数据

    在上一个示例中,咨询室(指导教师的办公室号码)在功能上取决于“指导教师”属性。 解决方案是将该属性从“学生”表移动到“教职员工”表,如下所示:

    学生:

    学生编号 指导教师
    1022 Jones
    4123 Smith

    教职员工:

    名称 Room Dept
    Jones 412 42
    Smith 216 42