数据库设计理论及应用(2)——范式理论
Monday, December 22nd, 2008该系列计划包括5部分:完整性约束理论及应用、范式理论及应用、需求分析、概念结构设计、逻辑结构设计。本文是第二部分,介绍范式理论的相关概念及应用。 1.引言 假设我们设计学生表为:学生(学号,姓名,系别,系主任,宿舍楼) 学号 姓名 系别 系主任 宿舍楼 95001 张三 计算机科学系 李世民 宿5 95002 李四 计算机科学系 李世民 宿5 95003 王五 计算机科学系 李世民 宿5 …… …… …… …… …… 如果系名由“计算机科学系”改为“计算机科学与技术系”,我们要修改n条记录。同样,系主任更换后,或者改宿舍楼,也要修改n条记录。这说明这样的设计不是一个好的设计。 范式理论可以指导我们完成一个好的设计。 2.范式理论 2.1 1NF 定义4:对关系的最起码的要求是:每个分量必须是不可分的数据项。满足这个关系模式就属于第一范式(1NF)。 如上面的例子就属于1NF,当然,满足1NF不一定就是好的设计。 2.2 函数依赖 分析数据库表,以上面的例子为例,如果我们知道了某个学生的学号,如95001,我们就能确定其姓名、系别等信息。我们称学号函数确定姓名,学号函数确定系别。 定义5:设R(U)是属性集U上的关系模式。X,Y是U的子集。若对R(U)中的关系r,r中不可能存在两个元组在X上的属性值相等,而在Y上属性值不等,则称X函数确定Y或Y函数依赖于X,记作X→Y。 例7:选修( 学号, 课程号, 成绩) (函数确定符号左边加个竖线表示不能函数确定,呵呵)。 定义6:在R(U)中,如果X→Y,并且对于X的任何一个真子集X’,都有 ,则称Y对X完全函数依赖,记作: 。 若X→Y,但Y不完全函数依赖于X,则称Y对X部分函数依赖,记作: 例8:选修(学号,姓名,课程号,成绩) 因为:学号→姓名,所以: 定义7:在R(U)中,如果X→Y(Y ⊈ X),Y→Z, ,则称Z对X传递函数依赖,记作: 2.3 2NF 定义8:若RÎ1NF,且每一个非主属性完全依赖于码,则RÎ2NF 这里的非主属性,指不包括在任何候选码中的属性。(主属性指候选码的所有属性)。 例9:选修(学号,姓名,系别,宿舍楼,课程号,成绩) 我们用图形表示函数依赖关系。实线箭头表示完全函数依赖,虚线箭头表示部分函数依赖,假设我们的例子中,每个宿舍楼都属于某个系的,没有交叉住宿的情况。 图中,系别和宿舍楼都是完全函数依赖与学号,但部分函数依赖于(学号,课程号)。而(学号,课程号)为码,因此该例不属于2NF。 该例中,系别和宿舍楼出现的次数,与学生选课出现的次数一样多,显然不是一个好的设计。我们把它分解为第二范式,使数据冗余减少。 根据图示,按照2NF的定义,要使系别和宿舍楼完全函数依赖于码,需要将这个关系分解成两个关系模式。因为系别和宿舍楼仅完全函数依赖于学号,这样把这三个属性组成一个关系模式。成绩完全函数依赖于(学号,课程号),这三个属性组成另外一个关系模式: 选修(学号,课程号,成绩) 系别(学号,系别,宿舍楼) 分解后属于2NF,系别出现的次数与学号出现次数一样多,与原来相比明显减少。 2.4 3NF 定义9:若R中不存在这样的码X,对属性组Y及非主属性Z(Z ⊈ Y),使得X→Y( ),Y→Z成立,则RÎ3NF 也就是说,3NF中不能存在传递函数依赖。我们看例9的结果中系别那个关系模式。 例10:系别(学号,系别,宿舍楼) 这里,宿舍楼出现的次数与学号出现的次数一样多,显然也存在数据冗余。我们画出它的函数依赖。 从图中可以看出,是学号à系别à宿舍楼形成的传递函数依赖,要消除传递函数依赖,把这个传递打断即可。因此分解成两个关系模式: 学生系别(学号,系别) 住宿(系别,宿舍楼) 2.5 其它范式 定义10:若R∈1NF,若X→Y且Y⊈X时X必包含码,则RÎBCNF 1NF~3NF还是比较简单的,BCNF就麻烦一些了。3NF的“不彻底”性表现在可能存在主属性对码的部分依赖和传递依赖。对于初学者,设计到3NF就是比较高的水平了,BCNF就不举例说明了。 至于4NF和5NF,涉及到多值依赖的概念,理解起来比较困难,就不说了。 3.使用低级范式的理由 有的人喜欢用低级范式设计数据库,理由是“方便”。这种理由是站不住脚的,所谓方便无非是查询时不用很复杂的SQL语句,实际上如果查询语句非常复杂,我们完全可以用视图实现,应用程序则从视图上查询,这样查询语句不会很复杂,同时保持了数据冗余小的优点。 使用低级范式的正当理由应该是设计比较麻烦,虽然这个理由看上去有偷懒的嫌疑。因为数据库设计不是给定无限时间进行设计,往往工期都比较紧张,因此应该是在时间和能力范围内使用尽可能高的范式级别。因为3NF比较简单,正常情况下,要求到3NF是合理的。 我自己在设计数据库时,大部分也是分析到BCNF为止。后面再分析,要花费很多时间,还不一定对数据库性能提高多少。当然,主要原因还是我偷懒。