BCNF(巴斯范式)与反范式设计

反范式设计是什么,有了范式设计,为什么还需要反范式设计。反范式设计适用的场景是什么?存在什么问题
3NF有什么不足?除了3NF,我们为什么需要BCNF。

BCNF(巴斯范式)

有如下仓库warehouse_keeper表, 一个仓库只有一个管理员,同时一个管理员也只能管理一个仓库
BCNF(巴斯范式)与反范式设计

  • 候选键:(管理员,物品名) (仓库名,物品名)
  • 主键:(仓库名,物品名)
  • 主属性:仓库名,管理员和物品名
  • 非主属性:数量

如何判断一张表的范式?我们需要根据范式的等级,从低到高判断。

  1. 数据库每个属性都是原子性的,符合1NF的要求
  2. 数据表中的非主属性 数量 都与候选键全部依赖, (仓库名,物品名)决定数量, (管理员,物品名)决定数量,因此,符合2NF的要求
  3. 数据表中的非主属性,不传递依赖于候选键。因为符合3NF的要求

既然数据表已经符合3NF的要求,是不是就不存在问题呢?

  1. 增加一个仓库,但是没有存放任何物品。根据数据表实体完整性的要求,主键不能有空值,因此会出现插入异常
  2. 如果仓库更换了管理员,我们就可能会修改数据表中的多条记录
  3. 如果仓库里面的商品都卖空了,那么此时仓库名称和相应的管理员名称也会随之被删除

所以,即便数据表满足3NF的要求,同样存在插入,更新和删除数据的异常情况

造成这种异常的原因是: 主属性仓库名对候选键(管理员,物品名)是部分依赖的关系,这样就有可能导致上面的异常情况。

BCNF:人们在3NF的基础上进行了改进,提出了BCNF,也叫做巴斯-科德范式,它在3NF的基础上消除了主属性对候选键的部分依赖或者传递依赖的关系

根据BCNF的要求,我们将仓库管理关系表 拆分成下面的这样

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

这样就不存在主属性对于候选键的部分依赖或传递依赖,上面数据表的设计就符合BCNF

反范式设计

越高阶的范式得到的数据表越多,数据冗余就越低。但有时候,我们设计数据表的时候,需要为了性能和读取效率违反范式化得到原则。反范式就是允许少量的冗余,通过空间换时间

比如商品表和用户表,我们每次 查询商品的时候需要展示用户名字,这个时候可以再新建一张表,和商品表保持一致,并且将用户名字段也加载里面,然后就不需要每次查询都连表,增加查询效率。新建的冗余表,注重数据同步

反范式存在的问题和适用场景

存在的问题:
在数据量小的情况下,反范式不能体现性能的优势,可能还会让数据库的设计更加复杂。

  • 比如采用存储过程来支持数据的更新、删除等额外操作,很容易增加系统维护的成本
  • 比如用户每次更改昵称的时候,都需要执行存储过程来更新,如果昵称更改频繁,会非常消耗系统资源。

使用场景:

  • 当冗余信息有价值或者能大幅度提高查询效率的时候,我们就看可以采取反范式的优化。
  • 常用于数据仓库的设计中,因为数据仓库通常存储历史数据,对增删改的实时性要求不强,对历史数据的分析需求强。

数据仓库和数据库在使用上的区别

  1. 数据库设计的目的在于捕获数据,而数据仓库的设计目的在于分析数据
  2. 数据库对数据的增删改实时性要求强,需要存储在线的用户数据,而数据仓库的一般都是历史数据
  3. 数据库设计需要尽量避免冗余,但为了提升查询效率也允许一定的冗余性,而数据仓库在设计上更偏向于采用反范式设计

总结

范式设计越高阶,数据表就会越精细,数据的冗余度也就减少,在一定程度上可以让数据库在内部关联上更好的组织数据。但有时候我们也需要采用反范式进行优化,通过空间来换取时间。

范式本身没有优劣之分,只有使用场景不同。没有完美的设计,只有合适的设计,我们在数据表的设计中,还需要根据需求将范式和反范式混合使用。