关于数据库范式的讲解
数据库范式是一种设计数据库的方法,在数据库这门学科来说,我认为这是一个比较难的点,以至于有很多工作多年的工程师以及考研考证的小伙伴没有真正的弄懂,因此我翻阅了大量的资料,希望能用通俗易懂的方式给大家讲解一下第一范式、第二范式、第三范式以及BC范式到底是什么,帮助大家能独立设计出高质量且规范化的数据库表。
函数依赖
要说范式,那么我们应该先谈谈什么叫做函数依赖,函数依赖分两种,分别是部分函数依赖以及传递函数依赖,接下来我们会逐一介绍。
部分函数依赖:
当1个关系模式中主键由2个及以上的属性组成时,非主属性只依赖于其中1个主属性,就是部分函数依赖。举一个例子,属性集{用户号,用户地址,公寓号,公寓楼层数},主键是2个主属性(用户号+公寓号),公寓号决定了公寓楼层数,所以公寓楼层数依赖于公寓号,不依赖于用户号,公寓楼层数只依赖于主键的其中1个主属性,也就是说用户号+公寓号可以决定公寓楼层数,公寓号自己也可以决定公寓楼层数,所以就是部分函数依赖。
传递函数依赖:
当关系模式中,出现非主属性决定非主属性时,就是传递函数依赖。举一个例子,属性集{用户号,用户地址,公寓号,公寓楼层数},主键是用户号,用户号决定公寓号,公寓号决定公寓楼层数,且公寓号、公寓楼层数都属于非主属性,那么就是传递函数依赖。
第一范式1NF
第一范式指的是关系中的每一个分量必须是一个不可分的数据项,简单来说就是表中不允许有小表的存在。下面我们来举一个例子:
用户号 | 用户姓名 | |
---|---|---|
姓 | 名 | |
1 | ouyang | feng |
如果出现这种情况,我们就说他不满足第一范式,而我们在日常的开发过程中,基本都是满足第一范式的,很少或者几乎没有不满足的。
第二范式2NF
如果关系R属于1NF,且每一个非主属性完全函数依赖于任何一个候选码,则R属于2NF,简单点来说,2NF就是在1NF的基础上,表中的每一个非主属性不会依赖复合主键中的某一列,就是不可以有部分函数依赖。当表不满足第二范式的时候,我们应该进行拆表,使其满足第二范式。
再说一下什么时候会出现部分函数依赖,当主键含有多个属性的时候才会出现,主键只有一个属性是不会出现部分函数依赖的,因为部分函数依赖指的是主键的一部分,主键只有一个的话就没有部分,所以主键只有一个属性的时候必然是第二范式。
下面我们来举一个例子:
用户号 | 用户姓名 | 所在公寓 | 公寓楼层数 | 房间号 | 当月产生费用 |
---|---|---|---|---|---|
202402 | 张三 | 公寓01 | 9 | 101 | 2000 |
202403 | 李四 | 公寓01 | 9 | 102 | 2100 |
202403 | 李四 | 公寓01 | 9 | 103 | 2200 |
202403 | 李四 | 公寓01 | 9 | 104 | 2300 |
上表所述的依赖关系是(用户号->用户姓名,用户号->公寓号,公寓号->公寓楼层数,用户号->房间号,用户号,房间号->当月产生费用)
由此可见,用户号和房间号能决定该房间当月产生的费用,但是用户号又可以决定用户姓名、公寓号和房间号,很明显存在部分函数依赖,所以不满足第二范式,因此我们要对其进行拆表改进。
可以把上述表拆分成:
用户(用户号,用户姓名,公寓号,公寓名称,公寓楼层数)用户号是主键
租房(用户号,房间号,当月产生费用)用户号和房间号是联合主键
那么这两张表都满足第二范式,但是不满足第三范式
第三范式3NF
在满足1NF的基础上,表中不存在非主属性对码的传递依赖,简单点来说就是表中不可以存在传递依赖。
继续上面的实例,就不属于3NF,因为用户号决定了公寓号,公寓号又决定公寓名称和公寓楼层数,因此存在非主属性对主属性的传递依赖。
我们可以将表进一步分解为:
用户(用户号,用户姓名,公寓号)用户号是主键
公寓(公寓号,公寓名称,公寓楼层数)公寓号是主键
租房(用户号,房间号,当月产生费用)用户号和房间号是联合主键
每张表都满足第三范式3NF
BC范式BCNF
这里要先说一个概念,候选键可以是多个,主键是候选键里面任选一个,因此候选关键字是可以有多种情况的,候选键里面又可以有多个元素。举一个例子:有一张用户表(用户姓名,身份证,手机号),其中用户姓名和身份证可以唯一标识,用户号和手机号也可以唯一标识,那么候选关键字就可以有两种情况了。前面说的1NF、2NF、3NF都是一种情况。
BC范式是指在第三范式的基础上进一步消除主属性对于码的部分函数依赖和传递依赖。
简单点来说,就是每一种情况下,每一个依赖的左边决定因素都必然包含候选键。
举一个例子:有一个依赖集合{SJ->T,T->J},组合键为(S,T)或者(S,J),S和J可以推出T,T可以推出J,由此可知,STJ三个属性都是主属性,因此其达到了3NF,(不存在非主属性,不存在传递依赖)。然而,第二种情况,即(S,J)为候选键的时候,对于依赖T->J,T在这种情况不是候选键,即T->J的决定因素不包含任意候选码,因此不满足BCNF。
要转换成BCNF也简单,只需要将依赖T->J变成TS->J即可,这样其左边决定因素就包含了候选键之一S。
结语
上面就是我对数据库范式的理解,希望可以帮助到大家,如果有要完善的地方,欢迎大家在评论区留下宝贵的建议,感谢!