关系型数据库范式

db-normalization

设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。

目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。

此文修改整理自:https://www.zhihu.com/question/24696366/answer/29189700

01. 一些概念

范式

范式是“符合某一种级别的关系模式的集合,表示一个关系内部各属性之间的联系的合理化程度”。实际上你可以把它粗略地理解为 一张数据表的表结构所符合的某种设计标准的级别

关系 与 关系模式

“关系”和“关系模式”的区别,类似于面向对象程序设计中”类“与”对象“的区别。”关系“是”关系模式“的一个实例,你可以把”关系”理解为一张带数据的表,而“关系模式”是这张数据表的表结构。

元组

可以把“元组”理解为一张表中的每条记录,也就是每一行。

属性

关系里的列。

关系中的某个属性或者某几个属性的组合,用于区分每个元组。

主属性

包含在任何一个码中的属性称为主属性。

异常

  • 插入异常:无法单独新添加一个系,因为每个系是伴随着学生而存在于这张表中的。
  • 删除异常:若将某个系中的全部学生记录都删掉,那么这个系也不复存在了。
  • 修改异常:假如李小明转系到法律系,那么为了保证数据库中数据的一致性,需要修改三条记录中系与系主任的数据。
  • 数据冗余:每一名学生的学号、姓名、系名、系主任这些数据重复多次。每个系与对应的系主任的数据也重复多次。

函数依赖

若在一张表中,在属性(或属性组)X 的值确定的情况下,必定能确定属性 Y 的值,那么就可以说 Y 函数依赖于 X,写作 X → Y

也就是说,在数据表中,不存在任意两条记录,它们在 X 属性(或属性组)上的值相同,而在 Y 属性上的值不同。这也就是“函数依赖”名字的由来,类似于函数关系 y = f(x),在 x 的值确定的情况下,y 的值一定是确定的。

部分函数依赖

假如 Y 函数依赖于 X,但同时 Y 并不完全函数依赖于 X,那么我们就称 Y 部分函数依赖于 X。

完全函数依赖

在一张表中,若 X → Y,且对于 X 的任何一个真子集(假如属性组 X 包含超过一个属性的话),X → Y 不成立,那么我们称 Y 对于 X 完全函数依赖

传递函数依赖

假如 Z 函数依赖于 Y,且 Y 函数依赖于 X (严格来说还有一个 X 不包含于 Y,且 Y 不函数依赖于 Z 的前提条件),那么我们就称 Z 函数传递依赖于 X 。

02. 1NF

定义:符合 1NF 的关系中的每个属性都不可再分

上图中的表就不符合 1NF 的设计规范。

事实上,你在关系型数据库中创建的表,都一定满足 1NF 规范。类似于下面的表这样:

在符合 1NF 的数据库设计中可能存在着 异常 ,所以我们需要提高设计标准,去掉导致上述四种问题的因素,使其符合更高一级的范式(2NF),这就是所谓的“规范化”。

03. 2NF

定义:2NF 在 1NF 的基础之上,消除了非主属性对于码的部分函数依赖

在上表中,学生信息与课程信息全混在了一张表中:

这里的码是 (学号,课名),用它来标识每个元组。

对于 (学号,课名) → 姓名,有 学号 → 姓名,存在非主属性 姓名 对码(学号,课名) 的部分函数依赖。 对于 (学号,课名) → 系名,有 学号 → 系名,存在非主属性 系名 对码(学号,课名) 的部分函数依赖。 对于 (学号,课名) → 系主任,有 学号 → 系主任,存在非主属性 系主任 对码 (学号,课名) 的部分函数依赖。

所以存在非主属性对于码的部分函数依赖,最高只符合 1NF 的要求,不符合 2NF 的要求。

这时候需要对这张表进行拆分:

04. 3NF

定义:3NF 在 2NF 的基础之上,消除了非主属性对于码的传递函数依赖

对于上图中的 选课 表,主码为 (学号,课名),主属性为 学号课名,非主属性只有一个,为 分数,不可能存在传递函数依赖,所以 选课 表的设计,符合 3NF 的要求。

对于上图中的 学生 表,主码为 学号,主属性为 学号,非主属性为 姓名系名系主任。因为 学号 → 系名,同时 系名 → 系主任,所以存在非主属性 系主任 对于码 学号 的传递函数依赖,所以 学生 表的设计,不符合 3NF 的要求。

为了让数据表设计达到 3NF,我们必须进一步进行模式分解为以下形式: 选课(学号,课名,分数) 学生(学号,姓名,系名) (系名,系主任)

05. BCNF

若:

  1. 某公司有若干个仓库;
  2. 每个仓库只能有一名管理员,一名管理员只能在一个仓库中工作;
  3. 一个仓库中可以存放多种物品,一种物品也可以存放在不同的仓库中。每种物品在每个仓库中都有对应的数量。

基于此关系模式的关系(具体的数据)可能如图所示:

函数依赖集:仓库名 → 管理员,管理员 → 仓库名,(仓库名,物品名)→ 数量 :(管理员,物品名),(仓库名,物品名) 主属性 :仓库名、管理员、物品名 非主属性 :数量

∵ 此关系模式中不存在 非主属性 的 部分函数依赖 和 传递函数依赖。

∴ 此关系模式符合 3NF。

但是在某些特殊情况下,即使关系模式符合 3NF 的要求,仍然存在着插入异常,修改异常与删除异常等问题,仍然不是 “好” 的设计。

造成此问题的原因:存在着 主属性 对于 码 的 部分函数依赖 与 传递函数依赖。在此例中就是存在主属性 仓库名 对于码的部分函数依赖。

解决办法就是要在 3NF 的基础上消除 主属性 对于 码 的部分与传递函数依赖:

仓库(仓库名,管理员) 库存(仓库名,物品名,数量)