数据库范式
范式,Nomal form,简称NF。在关系型数据库中,想要设计出一个好的表关系结构,就必须使关系满足于一定的约束条件,这里说的约束条件形成了规范,可称之为数据库范式。
数据库范式分成了几个等级,一级比一级要求更加严格,范式消除了重复数据从而减少了冗余数据,让数据库内的数据有更好的组织,另外,满足高等级的范式前提条件是满足低等级范式。
这里仅介绍数据库的三大范式。
第一范式(1NF)
第一范式,指关系模型中,每一个属性都应该是原子性的,即数据库表的每一列都是不可分割的基本数据项,而不能是集合、数组、记录等非原子数据项。
举个例子,如下数据库表1所示:
Stu_ID(主键) | Stu_Name | Stu_Address | Course_ID(主键) | Course_Name | Course_Description |
---|---|---|---|---|---|
001 | 小明 | 广东省广州市天河区 | X1 | 操作系统 | 课程描述1 |
002 | 小温 | 广东省广州市海珠区 | X2 | 数据结构 | 课程描述2 |
003 | 小红 | 广东省广州市越秀区 | X3 | Java开发 | 课程描述3 |
表1说明:Stu_ID为学生ID,为表1主键; Course_ID为学生课程ID,为表1主键;Stu_Name为学生姓名;Stu_Address为学生所在地址;Course_Name为学生课程名称;Course_Description为学生课程描述。
如上所示,表1中列属性Stu_Address是可以进行分割的,不为原子数据项,例如“广东省广州市天河区”可以分割为“广东省”、“广州市”和“天河区”,故当前数据库表不符合第一范式(1NF),为了使数据库表符合第一范式(1NF),可将非原子数据项进行分割,使每一数据库表列属性都保持原子性,可拆分如下表2:
Stu_ID(主键) | Stu_Name | Stu_AddrProvince | Stu_AddrCity | Stu_AddrArea | Course_ID(主键) | Course_Name | Course_Description |
---|---|---|---|---|---|---|---|
001 | 小明 | 广东省 | 广州市 | 天河区 | X1 | 操作系统 | 课程描述1 |
002 | 小温 | 广东省 | 广州市 | 海珠区 | X2 | 数据结构 | 课程描述2 |
003 | 小红 | 广东省 | 广州市 | 越秀区 | X3 | Java开发 | 课程描述3 |
第二范式(2NF)
第二范式,即在第一范式的基础上,非码属性必须完全依赖于候选码,而不是依赖于部分的主码。
这里顺带对一些概念进行解释:
- 候选码:关系中的某一属性组的值能唯一地标识一个元组,而其子集不能,就称该属性组为候选码;比如说以上数据库表2中Stu_ID为候选码,同样Course_ID为候选码;特别注意,候选码是属性组,即可以是一到多个列属性,比如说我们可以假定(Stu_ID,Course_ID)这属性组为候选码,必须严格按照两个属性共出现的形式,去标识一个元组;
- 主码:一个关系有多个候选码时,则选定其中一个为主码;比如说以上数据库表2中Stu_ID和Course_ID都为候选码,这时候有两个候选码,我们可以选定Stu_ID为主码,当然也可以选定Course_ID为主码;另外,主码即主键;
- 主属性:候选码的诸属性称为主属性,比如数据库表2中的“001”、“002”和“003”;
- 非主属性:不包含在任何候选码中的属性称为非主属性,比如数据库表2中的“小明”、“广东省”、“广州市”、“海珠区”、“Java开发”等;另外,也称之为“非码属性”;
我们再看回以上表2,其中Stu_Name等相关学生信息列属性字段由Stu_ID主键决定,同理Course_Name是由主键Course_ID决定,此时非码属性没有完全依赖于候选码,每个非码属性只是依赖于部分的主码,比如说Stu_Name是由Stu_ID决定而不需要Course_ID决定,故当前数据库表2不符合第二范式(2NF),为了使数据库表符合第二范式(2NF),可将表2进行拆分为以下表3和表4:
Stu_ID(主键) | Stu_Name | Stu_AddrProvince | Stu_AddrCity | Stu_AddrArea |
---|---|---|---|---|
001 | 小明 | 广东省 | 广州市 | 天河区 |
002 | 小温 | 广东省 | 广州市 | 海珠区 |
003 | 小红 | 广东省 | 广州市 | 越秀区 |
Course_ID(主键) | Course_Name | Course_Description |
---|---|---|
X1 | 操作系统 | 课程描述1 |
X2 | 数据结构 | 课程描述2 |
X3 | Java开发 | 课程描述3 |
第三范式(3NF)
第三范式,即在第二范式的基础上,任何非主属性不依赖于其他非主属性(在2NF基础上消除传递依赖)。
如表4所示,我们可以得到这样的传递依赖,由主码【Course_ID】决定【Course_Name】,再而【Course_Name】得出【Course_Description】,即Course_ID–>Course_Name–>Course_Description,故当前数据库表4不符合第三范式(3NF),为了使数据库表符合第三范式(3NF),可以将表4进行拆分表5和表6:
Course_ID(主键) | Course_Name |
---|---|
X1 | 操作系统 |
X2 | 数据结构 |
X3 | Java开发 |
Course_Name | Course_Description |
---|---|
操作系统 | 课程描述1 |
数据结构 | 课程描述2 |
Java开发 | 课程描述3 |
另外更高等级的范式不再进一步介绍。
在一般的项目开发中,我们对关系型数据库表关系的规划中,往往到第三范式之上的BC范式(BCNF)为止,很少会精确到第四范式;亦或者会停留在第二范式或者第三范式即可。因为我们从上述的介绍中可以看到,为了符合范式规则,从一张数据库表不断拆分,衍生出多表,在实际项目中,如果频繁需要取多表的数据难免造成内存压力和时间成本压力,故为了提高效率,往往舍去不必要的高范式,低范式往往性价比更高。
以上,就是对数据库三大范式所有说明介绍。