前言
最近工作中负责一个项目的开发,其中涉及到的数据表比较多,所以特意重拾了一下大学的知识,写一篇博客记录一下。
定义
范式的英文名为Normal Form
,是E.F.codd
提出来的。通俗讲就是数据库的规范和准则。
而这些规范和准则会被分为多个等级,满足某个等级的数据库设计就会被称为第几范式。满足最低要求的叫第一范式,简称1NF;在第一范式的基础上满足进一步要求的称为第二范式,简称2NF,其余范式以此类推。
高等级的范式是低等级范式的真子集,即满足第二范式的数据库设计一定也满足于第一范式。
这篇博客因为篇幅问题,只记录前三范式。
第一范式
第一范式强调列的原子性,即每个列不可再分。
第一范式是一定要遵守的准则,它代表着数据库的每个属性都是有基本元素构成的。这些基本元素可以是varchar、int、bool
等,下面是例子:
看到了吧,在第三行的address
这个字段,它可以存储公司地址亦可以存储家庭地址。这样的设计就容易引起歧义,不符合1NF,我们可以对其进行拆分,分成(id,name,company_addr,home_addr,…),这样保证了原子性,符合1NF。
第二范式
在大学时,书本是这样介绍第二范式的,数据库内的表,任意非主键字段都要对主键字段完全依赖。
大白话是:所有主键只有一个字段的表,都符合2NF。
如果存在多关键字的表,必须这些多关键字一块才能决定其他非关键字,否则则不符合第二范式。
如图,一个采购购买表。可以看出商品和采购者是一个多对多的关系,只有这两个相结合才可以准确得出一个采购单的详细信息。这个就符合我们上文说的多关键字数据表。
但是有个问题,goods_name
可以得出price
,purchaser
可以得出phone
等等。这里就不符合我们说的2NF了。
其他非关键字(price,nums,phone
)必须完全由主关键字组合(goods_name,purchaser
)才能推出。
这里可以考虑拆分表:
订单表经过拆分后,避免了非关键字对关键字的部分依赖,消除了冗余数据,保证了2NF。
第三范式
在2NF的基础上,非关键字必须直接依赖于主键,不能存在传递依赖。
即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
还是拿一个订单表举例子:
例子和2NF的例子基本相同,不同的是order(订单表)。
这里首先只有一个关键字(ID)订单ID,满足2NF。其中nums,amount,purchaser_id
直接依赖于主键,但是purchaser_name,phone
却依赖于非关键字purchaser_id
,这里它们两在订单表里就是传递依赖于主键了,而不是直接依赖。不符合第三范式。
怎么改呢?其实在2NF的例子就已经改好了,各位可以参考下。
但是在实际开发中,订单表的查询是特别频繁的,这个时候连表查询会损耗特别多的性能,也就是不一定非要满足于3NF,可以根据现实情况调整。但前提是采购者和商品的信息不可随意修改。