数据库设计中的范式

发表于2019-09-28,长度1595, 57个单词, 4分钟读完
Flag Counter

数据库范式是大学课程中就学过的东西。不过虽然大家都知道,但是少有人能谈得上掌握。另外实际生产中,由于开发规范的限制,有时候不得不特意违反范式设计。

第一范式 1NF

范式的英文是normal form,所以简写NF。

第一范式最简单,所有的列不可再分。现在的数据库都符合1NF,你没法设计一个表是违反1NF且能用于检索的。

第二范式 2NF

第二范式简单点说就是表有唯一主键,这个主键可以是组合键。要满足2NF必须先满足1NF。

如果没有其他范式要求,那2NF就这么简单。

由于后面出现了更多更严格的要求,2NF的内涵也增加了:要求非主键列完全依赖于主键。

既然提到“完全”,就有不完全,这就涉及到组合键,因为一个键没有完全不完全的概念。一个表的主键是联合主键,并且非主键必须同时依赖联合键,不能只依赖于联合键中的部分。否则就是违反2NF。

在目前公司我没有接触过联合主键(因为永辉的联合主键都被合在一起了),这里参考一个表:订单明细表。这个表的主键是订单号拼接一个4位的序列号做为明细号,序列号是每个订单从1递增的。假如对其改造,将其主键拆分为订单号和明细序号的组合(order_id, item_id),如果其他字段有只依赖订单而不依赖明细的就属于违反2NF。比如说有个字段是收货人,因为订单只有一个收货人,所以明细的收货人都相同,所以就违反了2NF,应该把收货人放在订单表上。当然实际就是这样设计的。

3NF

第三范式必须先满足第二范式,在2NF基础上,非主键列必须直接依赖主键,不能传递依赖。出现传递依赖的就应该放在其他表中。这个在日常设计中我们违反的特别多,就是常说的“数据冗余一下”,所以是特意违反。

3NF有这么几个内涵:

  • 非主键字段没有依赖非主键字段;
  • 非主键字段没有函数依赖非主键字
  • 表外键是父表主键
  • 关联记录中的非主键完全不同

当然上面几条都说的同一个意思。比如联营小票表,成本字段=小计1-小计4+小计5,这个字段就和主键没有直接关系,是通过几个非主键字段计算出来的,属于典型的函数依赖。另外里面已经记录了商品编码,又额外记录了商品名称等冗余字段(因为商品数据在其他数据库,甚至是其他实例),就属于商品名称直接依赖商品编码而非依赖主键。

因为商业开发中禁用外键,所以一般不会有外键问题。

BC NF

BC范式是在满足3NF的基础上要求:主属性不能依赖主属性。

它出现的场景是当有联合主键时,主键内的字段不能依赖其他主键字段(主键外的依赖在2NF中已经限制了)。

我们不会有这种场景,因为没有联合主键;另外如果你找出了一个违反BC范式的表,估计它已经提前违反了3NF。

4NF

第四范式也要求先满足3NF(满足第四范式就自动满足了BC范式),然后要求:非主键字段不能有多值。

第四范式的违反会让表难以设计,因为非主属性有多值就会导致主键相同但需要插入多条记录。

这时候只能要么把多值字段加入主键,要么把表拆分。

所以实际开发中,如果满足了BC范式就满足了第四范式,尽管要求不同,但效果上BC NF == 4NF。

5NF

第五范式是在满足之前要求的基础上,如果拆成多个二元关系表会丢失信息就满足第五范式;否则就应该拆分。

比如顾客购买表(顾客,商品,门店)满足4NF。是否满足5NF呢?

将其拆成(顾客,商品)和(顾客,门店)和(商品,门店)三个表是否会引起信息丢失呢?

第一个表表明顾客买过哪些商品,第二个表说明顾客在哪买的商品,第三个表说明哪个门店出售过哪个商品。但是没法知道顾客买的商品是从哪里买的。所以不能拆分。

这个我们开发中也没碰到。

结论

1NF、4NF、5NF我们不用特意理会就能满足。

数据库范式的出现是为了减少(减灭)冗余数据,节省空间,提高数据保存和读取效率。但是在实际开发中,通常会基于不同目的特意冗余数据。

是否要遵守范式设计,就要考虑DB性能、应用性能、网络性能等因素。尽量满足,除非有特殊目的。

Written on September 28, 2019
分类: dev, 标签: database
如果你喜欢,请赞赏! davelet