数据库设计-范式

范式是符合某一种级别的关系模式的集合。关系型数据库中的关系必须满足一定的要求,满足不同程度要求的为不同范式。
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、Boyce-Codd 范式(BCNF)、第四范式(4NF)和第五范式(5NF)。
范式越高,冗余最低,一般到三范式即可,再往上,表越多,可能导致查询效率下降。所以有时为了提高运行效率,可以让数据冗余

一、第一范式(1NF):确保每列的原子性

数据表中的每一列(每个字段)必须是不可拆分的最小单元

用户 ID 姓名 电话
10001 张三 0755-88888888 18888888888

上面的电话字段可以继续分固定电话和手机

用户 ID 姓名 固定电话 手机
10001 张三 0755-88888888 18888888888

二、第二范式(2NF):非键字段必须依赖于键字段

如果一个关系满足 1NF,并且除了主键以外的其它列,都依赖于该主键。也就是说在一个数据库表中必须有一个主键,没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。

比如说要设计一个订单信息表,所以要将订单编号和商品编号作为数据库的联合主键

订单编号 商品编号 商品名称 数量
000001 p00001 宝马 1

商品名称跟订单编号无关而仅仅跟商品编号有关,这里违反了 2NF 的设计原则,会存在如下问题:

  1. 数据冗余
    一个产品销售了 n 次,“商品名称”就重复 n 次。
  2. 更新异常
    若调整了某商品的名称,数据表中所有行的“商品名称”值都要更新,否则会出现同一个商品名称不同的情况。
  3. 插入异常
    假设要新增新的商品,暂时还没有订单。这样,由于还没有“订单编号”关键字,“商品编号”和“商品名称”也无法记录入数据库。
  4. 删除异常
    假设要一批商品,这些商品信息就应该从数据库表中删除,与此同时,销售信息也被删除了。

所以上面的表实际上可以拆分为

订单编号 商品编号 数量
000001 p00001 1
商品编号 商品名称
p00001 宝马

三、第三范式(3NF):确保每列都和主键列直接相关,而不是间接相关

在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。
满足第三范式的数据库表应该不存在如下依赖关系:

1
关键字段 → 非关键字段x → 非关键字段y

比如设计订单信息表

订单编号 商品编号 数量 业务员 Id 业务员姓名
000001 p00001 1 10001 张三

明显有 业务员姓名 -> 业务员 Id -> 订单编号 的依赖关系,它也会存在 数据冗余更新异常插入异常删除异常 的情况,上面表可以拆分为:

订单编号 商品编号 数量 业务员 Id
000001 p00001 1 10001
业务员 Id 业务员姓名
10001 张三

这样的数据库表是符合第三范式的,消除了 数据冗余更新异常插入异常删除异常

四、Boyce-Codd 范式(BCNF):主属性不依赖于主属性

在第三范式的基础上,数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖则符合第三范式。
假设仓库管理关系表为:

仓库编号 商品编号 管理员编号 数量
000001 000001 10001 10

假设一个管理员只在一个仓库工作;一个仓库可以存储多种物品。这个数据库表中存在如下决定关系:

1
2
(仓库编号,商品编号) →(管理员编号,数量)
(管理员编号,商品编号) → (仓库编号,数量)

所以,(仓库编号,商品编号)和(管理员编号,商品编号)都是候选关键字,表中的唯一非关键字段为数量,它是符合第三范式的。但是,由于存在如下决定关系:

1
2
(仓库编号) → (管理员编号)
(管理员编号) → (仓库编号)
  1. 删除异常:
    当仓库被清空后,所有”商品编号”和”数量”信息被删除的同时,”仓库编号”和”管理员编号”信息也被删除了。

  2. 插入异常:
    当仓库没有存储任何物品时,无法给仓库分配管理员。

  3. 更新异常:
    如果仓库换了管理员,则表中所有行的管理员编号 都要修改。

把仓库管理关系表分解为二个关系表:

仓库编号 商品编号 数量
000001 000001 10
仓库编号 管理员编号
10001 10001

这样的数据库表是符合 BCNF 范式的,消除了删除异常、插入异常和更新异常。

还可以这么说:若一个关系达到了第三范式,并且它只有一个候选码,或者它的每个候选码都是单属性,则该关系自然达到 BCNF

五、 第四范式(4NF):要求把同一表内的多对多关系删除。

当一个表中的非主属性互相独立时(3NF),这些非主属性不应该有多值。若有多值就违反了第四范式。

下面用户表符合 3NF ,但在某些情况下,比如说有两个手机号码时,这样的表还是不合理的,违反了 4NF。

用户 ID 姓名 固定电话 手机
10001 张三 0755-88888888 18888888888
10001 张三 0755-88888888 18888888889

就可以拆分为固定电话表(用户 ID,固定电话)和手机号码表(用户 ID,手机号码)

所以只有在某些特殊情况下,要考虑将表规范到第四范式。

六、 第五范式(5NF):最终范式。

满足第四范式条件下,表必须可以分解为较小的表,除非那些表在逻辑上拥有与原始表相同的主键。
比如一个销售信息表(销售人员,供应商,产品)。
在某些情况下,这个表中会产生一些冗余。可以将表分解为:

  • 销售人员供应商表(销售人员,供应商);
  • 销售人员产品表(销售人员,产品);
  • 供应商产品表(供应商,产品)