函数依赖的概念:设X,Y是关系R的两个属性集合,当任何时刻R中的任意两个元组中的X属性值相同时,则它们的Y属性值也相同,则称X函数决定Y,或Y函数依赖于X,记为X→Y。
函数依赖分为平凡函数依赖,非平凡函数依赖,完全函数依赖,部分函数依赖,传递函数依赖。
平凡函数依赖:当关系中属性集合Y是属性集合X的子集时(Y⊆X),存在函数依赖X→Y,即一组属性函数决定它的所有子集,这种函数依赖称为平凡函数依赖。
非平凡函数依赖:当关系中属性集合Y不是属性集合X的子集时,存在函数依赖X→Y,则称这种函数依赖为非平凡函数依赖。
完全函数依赖:设X,Y是关系R的两个属性集合,存在X→Y,但Y不函数依赖于X 的任何真子集,则称Y完全函数依赖于X。
部分函数依赖:设X,Y是关系R的两个属性集合,存在X→Y,若X'是X的真子集,存在X'→Y,则称Y部分函数依赖于X。
传递函数依赖:设X,Y,Z是关系R中互不相同的属性集合,存在X→Y,X不函数依赖于Y,Y→Z,则称Z传递函数依赖于X。
假设有如下学生选课关系模式:R(学号,姓名,课程号,课程名,成绩,院系号,院系名),其中(学号,课程号)为主码,则存在如下函数依赖:
(学号)→(姓名) 非平凡函数依赖
(学号,姓名)→(姓名) 平凡函数依赖
(学号,课程号)→(成绩) 完全函数依赖
(学号,课程号)→(课程名) 部分函数依赖,课程名只依赖于课程号
(学号)→(院系名) 传递函数依赖,(学号)→(院系号),(院系号)→(院系名)
假设有如下学生关系模式:R(学号,姓名,课程号,课程名,成绩),其中(学号,课程号)为主码。(学号,课程号)→(成绩),(学号)→(姓名),(课程号)→(课程名)。
这个关系模式有部分函数依赖,存在4个问题:
数据冗余太大: 每一个学生姓名重复出现,重复次数与该学生所选课程数相同;每一门课程名重复出现,重复次数与选修该课程的学生数相同,这将消耗不必要的存储空间。
更新异常: 学生修改姓名或课程修改课程名后,必须修改系统中所有选课有关的元组,如果某一个元组没有被修改,将会导致数据不一致。
插入异常: 如果新开一门课程,还没有学生选,就无法把这个课程的信息存入数据库。
删除异常: 如果学生全部毕业了,在删除学生信息的同时,把课程信息也丢掉了。
如将上面的关系模式分解为R1(学号,姓名)、R2(课程号,课程名), R3(学号,课程号,成绩)就不会出现上面的问题了。
假设有如下学生关系模式:R(学号,姓名,院系号,院系名,办公地),其中(学号)为主码。(学号)→(姓名,院系号),(院系号)→(院系名,办公地)。这个关系模式有传递函数依赖,存在4个问题:
数据冗余太大: 每一个院系名和办公地重复出现,重复次数与该系所有学生数相同,这将消耗不必要的存储空间。
更新异常: 某院系更换办公地后,系统必须修改与该院系学生有关的每一个元组,如果某一个元组没有被更换,将会导致数据不一致。
插入异常: 如果一个院系刚成立,没有学生,就无法把这个院系的信息存入数据库。
删除异常: 如果某个系的学生全部毕业了,在删除该系最后一个学生信息的同时,把这个院系的信息也丢掉了。
如将上面的关系模式分解为R1(学号,姓名,院系号)和R2(院系号,院系名,办公地)就不会出现上面的问题了。
因此,含有部分函数依赖,传递函数依赖的关系模式不是一个好的模式。规范化理论正是用来改造关系模式,通过分解关系模式来消除其中不合适的数据依赖,以解决插入异常、删除异常、更新异常和数据冗余问题。
第一范式是指一个关系模式的所有属性都是不可分的基本数据项。
关系模式R(学号,姓名,获奖),其中(学号)是主码,R不满足第一范式,因为一个学生可能获得多个奖项。为了使R满足第一范式,有两种处理方式:
①如果知道一个学生的获奖不超过3项,可以分解为R(学号,姓名,获奖1,获奖2,获奖3)。这种处理方式使得R满足第一范式,但当大部分学生获奖较少时,数据库中将产生大量的空值,同时可扩展性较差。
②将R分解为R1(学号,姓名)和R2(学号,获奖)两个关系模式。R1中(学号)作主码,R2中(学号)为外码,R2中(学号,获奖)作主码,这样避免了方式①的缺陷并使得R1和R2均满足第一范式。
如果一个关系模式满足第一范式,并且每个非主属性完全函数依赖于码,则称其满足第二范式。
关系模式R(学号,课程号 ,姓名,课程名,成绩),R满足第一范式,但不满足第二范式,因为(学号)→(姓名),(课程号)→(课程名),(学号,课程号)→(成绩)。
分解为三个关系模式:
R1(学号,姓名) (学号)为主码
R2(课程号,课程名) (课程号)为主码
R3(学号,课程号,成绩) (学号,课程号)为主码
上面三个关系模式均满足第二范式。
如果关系模式满足第二范式,并且不存在非主属性传递依赖于码,则称其满足第三范式。简而言之,第三范式就是属性不依赖于其它非主属性。
关系模式R(学号,姓名,院系号,院系名),R满足第二范式,但不满足第三范式,因为(学号)→(院系号),(院系号)→(院系名)。
分解为两个关系模式:
R1(学号,姓名,院系号) (学号)为主码
R2(院系号,院系名) (院系号)为主码
上面两个关系模式均满足第三范式。
如果关系模式满足第三范式,并且不存在主属性对非所在码(不包含本主属性的码)的传递依赖和部分依赖,则称其满足BC范式。
设有一个仓库管理关系模式R(仓库号,物品号,管理员号,数量)。 (仓库号,物品号)和(物品号,管理员号)均为候选码,上面关系是满足第三范式的,但不满足BCNF范式,因为(管理员号)→(仓库号)。
分解为两个关系模式:
R1(仓库号,物品号,数量) (仓库号,物品号)为主码
R2(仓库号,管理员号) (管理员号)为主码
上面两个关系模式均满足BCNF范式。
规范化的基本思想是逐步消除数据依赖中不合适的部分,使模式中的各关系模式达到某种程度的“分离”,即采用“一事一地”的模式设计原则,让一个关系描述一个概念、一个实体或者实体间的一种联系。若多于一个概念就把它“分离”出去。因此所谓规范化实质上是概念的单一化。
规范化的步骤:
①对1NF关系进行投影,消除原关系中非主属性对码的函数依赖,将1NF关系转换为若干个2NF关系。
②对2NF关系进行投影,消除原关系中非主属性对码的传递函数依赖,从而产生一组3NF关系。
③对3NF关系进行投影,消除原关系中主属性对码的部分函数依赖和传递函数依赖,得到一组BCNF关系。
以上三步也可以合并为一步:对原关系进行投影,消除决定属性不是侯选码的任何函数依赖。
关系型数据库规范化的目标是减少冗余和提高表设计的灵活性,但同时也增加了在查询数据连接查询的难度。
如果系统对查询的频率和性能要求很高,那么就不得不在效率和冗余上权衡,得到一个折中的解决方法。而折中的方式就是引入受控冗余来降低规范化程度。
在关系型数据库中,反规范化是指在数据库规范化后,为了提高数据检索性能,在某些局部降低规范化标准,引入适当的冗余的方法。
反规范化数据库不应该和从未进行过规范化的数据库相混淆,反规范化引入的冗余是一种受控的冗余。
反规范化常用的方法是合并1:1联系的表,合并1:n联系的表,复制1:n联系1端表中数据到n端,复制m:n联系中m端和n端数据到新产生的联系表中。