数据库范式

1.什么是范式

简单的说,范式是为了消除重复数据减少冗余,从而让数据库内的数据得到更好地组织,让磁盘空间得到更有效利用的一种标准化标准,满足高等级的范式的先决条件是满足低等级范式。(比如满足2NF一定满足1NF).

目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了。

本文将以一个demo来讲解1NF-5NF以及BCNF.

2.DEMO

下面的这个demo来自于SQL Server MVP的CareySon,原文链接为 http://www.cnblogs.com/CareySon/archive/2010/02/16/1668803.html,看了很多讲解范式的文章,目前发现就这篇最好,所以就暂时借用一下了。

我们先看一下一个未经范式化的表:

其中employeeId是员工id,departmentName是部门名称,job代表岗位,jobDescription是岗位说明,skill是员工技能,departmentDescription是部门说明,address是员工住址。

2.1 第一范式(1NF)

如果一个关系模式R的所有属性都是不可分的基本数据项,则R∈1NF.

简单的说,1NF就是每一个属性都是不可分的。不符合第一范式则不能称为关系数据库。对于上表,不难看出Address是可以再分的,比如”北京市XX路XX小区XX号”,这显然不符合第一范式,对其应用第一范式则需要将此属性分解到另一个表,如下:

2.2 第二范式(2NF)

关系模式R∈1NF,并且每一个非主属性都完全函数依赖于R的码,则R∈2NF.

码的定义为:表中可以唯一确定一个元组的某个属性(或者属性组),如果这样的码有不止一个,那么大家都叫 候选码,我们从候选码中挑一个出来做老大,它就叫主码(其实就是我们平常说的主键).

简单的说,是表中的属性必须完全依赖于全部主键,而不是部分主键。所以只有一个主键的表如果符合1NF,那一定符合2NF.

这样做的目的是进一步减少插入异常和更新异常。在上表中,departmentDescription是由主键DepartmentName所决定,但却不是由主键EmployeeID决定,所以departmentDescription只依赖于两个主键中的一个,故要departmentDescription对主键是部分依赖,对其应用第二范式后如下表:

2.3 第三范式(3NF)

关系模式R 中若不存在这样的码X、属性组Y及非主属性Z(Z  Y), 使得X→Y,Y→Z,成立,则称R ∈ 3NF。

简单的说,3NF是为了消除数据库中关键字之间的依赖关系,在上面经过2NF的表中,可以看出jobDescription是由job(job并非主键)所决定,则jobDescription依赖于job,可以看出这不符合3NF,对表进行3NF后的关系图为:

上表中,已经不存在数据库属性互相依赖的问题,所以符合第三范式。

2.4 BC范式(BCNF)

设关系模式R∈1NF,如果对于R的每个函数依赖X→Y,若Y不属于X,则X必含有候选码,那么R∈BCNF。

简单的说,BC范式是在第三范式的基础上的一种特殊情况,既每个表中只有一个候选键(在一个数据库中每行的值都不相同,则可称为候选键),在上面第三范式的noNf表中可以看出,每一个员工的email都是唯一的(难道两个人用同一个email??)则,此表不符合bc范式,对其进行bc范式化后的关系图为:

2.5 第四范式

关系模式R∈1NF,如果对于R的每个非平凡多值依赖X→→Y(Y  X),X都含有候选码,则R∈4NF。

简单的说,4NF是消除表中的多值依赖,也就是说可以减少维护数据一致性的工作。对于上面的BC范式化的表中,对于员工的skill,两个可能的值是”C#,sql,javascript”和”C#,UML,Ruby”,可以看出,这个数据库属性存在多个值,这就可能造成数据库内容不一致的问题,比如第一个值写的是”C#”,而第二个值写的是”C#.net”,解决办法是将多值属性放入一个新表,则第四范式化后的关系图如下:

而对于skill表则如下:

3.总结

可以简单的对各范式进行如下理解:

  • 一范式就是属性不可分割
  • 二范式就是要有主键,并且其他字段都依赖于该主键
  • 三范式就是要消除传递依赖
  • 四范式就是在3NF的基础上,消除表中的多值依赖

一般的关系型数据库只要满足3NF或BCNF即可,范式并非越高越好,因为应用的范式登记越高,则表越多。表多会带来很多问题:

  • 查询时需要连接多个表,增加了查询的复杂度
  • 查询时需要连接多个表,降低了数据库查询性能

而现在的情况,磁盘空间成本基本可以忽略不计,所以数据冗余所造成的问题也并不是应用数据库范式的理由。