数据库范式的理解
一、概念
1.函数:明确的数学上的关系,比如:总价=单价*数量。
2.函数依赖:已经知X,则有且只有Y,与之对应。比如:已经“学号1”,则有且只有“生日1”与之对应。区别于函数:函数依赖不是数学上的关系。
X→Y:Y函数依赖于X(通俗地讲:知道X是多少,就能推导出/得知 Y 是多少)
X!→Y:Y不函数依赖于X(通俗地讲:知道X是多少,不推导出/不能得知 Y 是多少)
3.完全函数依赖:设X,Y是关系R的两个属性集合,X’是X的真子集,存在X→Y,但对每一个X’都有X’!→Y,则称Y完全函数依赖于X。
即:X是(A1,A2,A3)的集合,如果Y完全函数依赖于A,则:
(A1)!→Y, (A2)!→Y, (A3)!→Y,
(A1,A2)!→Y, (A1,A3)!→Y, (A2,A3)!→Y
4.部分函数依赖:设X’,Y是关系R的两个属性集合,存在X’→Y,若X是X’的真子集,存在X→Y,则称Y部分函数依赖于X’。
即:X’是(A1,A2,A3,B)的集合,它的真子集X(A1,A2,A3),若存在X’→Y,X→Y,则称Y部分函数依赖于X’。
通俗地讲:Y依赖于X',也依赖于“ 部分的X' ”。
部分函数依赖与完全函数依赖的区别是:
完全函数依赖的意思是,集合X不能再拆分了,再拆分,便不能决定Y了;集合X也不能再添加元素了,再添加元素,便变成了部分函数依赖。集合元素不能增,不能减,叫完全函数依赖。
1.第一范式
(1)涵义:是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。
简言之:字段不可重复,不可拆分。
其实,不可拆分,需要根据实际情况进行判定。比如,一个学生的生日,可以认为是不可拆分的字段。但是,有时却可能拆分成:年,月,日。
(2)违反第一范式的害处
是不言而喻的。这是关系型数据库最基本的要求,否则,数据库都建立不起来。
2.第二范式
(1)涵义:非关键字段完全函数依赖于候选关健字。或者说,不存在【非关键字段部分函数依赖于候选关键字】。
如果要创建记录学生成绩的表,将(学号、姓名、性别、课程号、课程名、学分、成绩)置于同一张表中,则违反了第二范式。
解释如下:
A.关键字(学号+课程号),非关键字段:姓名、性别、课程名、学分、成绩。
B.成绩则完全函数依赖于关键字(学号+课程号),
姓名(或性别) 是 部分函数依赖于关键字(学号+课程号)【(学号+课程号)→姓名,学号→姓名】,
课程名(或学分) 是 部分函数依赖于关键字(学号+课程号)【(学号+课程号)→课程名,课程号→课程名】。
C.因为存在了姓名或课程名对关键字的部分函数依赖,所以,违反了第二范式。
通俗地讲:遵守第二范式,就是消灭部分函数依赖。
(2)违反第二范式的害处
丢失数据
假如只有以下三条记录,如何查询体育的学分(以上图七个字段置于同一表中为例子来说明)
因为如果没有学生选修体育,则而无法记录体育的学分信息。违反范式二,极有可能丢失重要的数据而没有记录。
学号 | 姓名 | 性别 | 课程号 | 课程名 | 学分 | 成绩 |
1 | 张三 | 男 | BB | 数学 | 2 | 99 |
2 | 李四 | 男 | BB | 数学 | 2 | 98 |
1 | 张三 | 男 | AA | 语文 | 4 | 97 |
(3)解决办法:
将表拆分。
拆分成四张表:(学号、姓名、性别);(课程号、课程名);(课程号、学分);(学号、课程号、成绩)
问:为何不是(课程号、课程名、学分)?
答:严格意义上,学分部分函数依赖于(课程号、课程名)二合一的关键字。但是,为了避免不必要的多表查询,而且课程号与课程名,课程名与学分都是一对一的关系,所以,仍然会使用(课程号、课程名、学分)。
3.第三范式
(1)涵义:不存在非关键字段对候选关键字的传递函数依赖。
如果要创建记录学生的班主任的表,将(学号、姓名、性别、班级、班主任)置于同一张表中,虽然并没有违反第二范式,但却违反了第三范式的。
解释如下:
A.因为存在学生重名的情况(姓名并不是一对一于学号,关键字只能是学号,单字段是唯一的候选关键字时,一定不存在部分函数依赖),所以表(学号、姓名、性别、班级、班主任)并没有违反第二范式。
B.存在传递函数依赖:班主任函数依赖于班级,班级函数依赖于学号,即 学号->班级->班主任【班级!→学号】。
通俗地讲:遵守第三范式,就是消灭传递函数依赖。
(2)违反第三范式的害处
数据冗余
插入异常:一个班级没有学生时,无法插入(班级、班主任)【主属性“学号”不能为空】;
修改异常:班级更换班主任时,有多少学生,就需要修改多少条记录;
删除异常:删除某班所有学生时,也将丢失班级与班主任的关系。
(3)解决办法
将表拆分
(学号、姓名、性别、班级);(班级、班主任)
* 符合第三范式的数据库设计,基本解决了数据冗余过大、插入异常、修改异常和删除异常的问题。但在实际使用中,往往为了性能和扩展的需求,只要做到第一范式或第二范式。
4.BCNF
(1)涵义:在满足第一、二、三范式的基础上,候选关键字内部各字段之间不存在函数依赖(包括完全/部分/传递函数依赖)。
第二范式和第三范式调整的是非关键字段与关键字的关系,消灭非关键字段对关键字的部分函数依赖和传递函数依赖。而BCNF消息灭的是关键字内部各字段之间的函数依赖关系。
如果要创建记录仓库物品数量的表,将(仓库号、存储物品号、管理员号、数量)置于同一张表中,虽然并没有违反第二、三范式,但却违反了BCNF的。
解释如下:
A.非关键字段只有一个:数量,候选关键字是:A(仓库号+存储物品号);B(管理员号+存储物品号)。“数量”对A和B,既没有部分函数依赖,也没有传递函数依赖,符合第二、三范式。
B.候选关键字内部:仓库号→管理员号;管理员号→仓库号
通俗地讲:遵守第BCNF,就是消灭关键字内部各字段之间的函数依赖。
(2)违反BCNF的害处
数据冗余
BCNF是对第三范式的修正,使数据库冗余度更小,不应被称为第四范式。
插入异常:一个仓库未指定管理员时,无法插入(仓库号、存储物品号、数量)【主属性“管理员号”不能为空】;
修改异常:仓库更换管理员时,有多少物品,就需要修改多少条记录;
删除异常:清空仓库,也将丢失仓库与管理员的关系。
(3)解决办法
将表拆分
(仓库号、存储物品号、数量);(仓库号、管理员号)
* 如果满足了BCNF,那么就不再会有任何由于函数依赖导致的异常,但是我们还可能会遇到由于多值依赖导致的异常。
5.第四范式
(1)涵义:满足BCNF,并且不包含多值依赖关系。
多值依赖的定义:表内字段全集U,被分为三个部分:X、Y、Z,它们的关系是:Z=U-X-Y,表内所有记录以 “group by X, Z”的方式进行分组,每组内有多个不重复的Y值,它们只由X值决定而与Z值无关【即:检索(X=x0 and Z=z0)时检出的一组Y值(y0,y1,y2...yn),这组Y值只由x0决定而与z0无关;且对于 每对(x,z)来说,情况都相同】,则我们称Y多值依赖于X。
数学定义:设R(U)是一个属性集合U上的一个关系模式,X, Y, 和Z是U的子集,并且Z=U-X-Y,多值依赖X->->Y成立当且仅当对R的任一个关系r,r在(X,Z)上的每个值对应一组Y的值,这组值仅仅决定于X值而与Z值无关。
通俗的讲:X值决定一组Y值【Z值靠边】
A.Y多值依赖于X时,如果每组有且只有一个Y值——其实就是Y函数依赖于X【函数依赖是多值依赖的特殊情况】,这种关键字内部的函数依赖属于BCNF要消灭的对象。
B.Y多值依赖于X时,如果Z为空集,则称Y平凡的多值依赖于X;如果Z不为空集,称Y非平凡的多值依赖于X。
C.Y多值依赖于X时,一定会有Z多值依赖于X(对称性,X值决定一组Y值时【Z值靠边】,X值一定也决定一组Z值【Y值靠边】)。
如果要创建记录教师学校教学科目的表,将(教师、学校、教学科目)置于同一张表中,虽然并没有违反BCNF,但却违反了第四范式。如下:
教师(X) | 学校(Z) | 教学科目(Y) |
张三 | A学校 | 矿物学 |
张三 | A学校 | 矿床学 |
张三 | B校 | 地质学基础 |
李四 | B学校 | 数据结构 |
李四 | C学校 | 宇宙第一编程语言 |
李四 | C学校 | 数据结构 |
李四 | D学校 | 数据结构 |
王五 | D学校 | 体育 |
王五 | D学校 | 定向越野 |
解释如下:
A.表内只有三个字段,共同构成关键字;没有非关键字,符合第二、三范式;它们之间没有函数依赖关系,符合BCNF。
B. 教师(张三)决定教学科目(矿物学、矿床学和地质学基础),但与学校(A学校、B校)无关;
教师(李四)、教师(王五)与教师(张三)情况一样【他们决定教学科目且和学校无关】
所有教师决定 “一组所教科目”,且均与学校无关。
所以,对于"学校"而言,“教学科目”多值依赖于"教师",
因学校非空,所以“教学科目”非平凡多值依赖于"教师"。
如果所有老师决定的“一组所教科目”的数量都只有一个,就变为“教学科目”函数依赖于“教师”。
对称性:对于"学校"而言,“教学科目”多值依赖于"教师",所以,对“教学科目”而言,“学校”多值依赖于“教师”:
教师(张三)决定学校(A学校、B校),但与教学科目(矿物学、矿床学和地质学基础)无关;
教师(李四)、教师(王五)与教师(张三)情况一样【他们决定学校且和教学科目无关】
所有教师决定 “一组学校”,且均所教科目无关。
通俗地讲:三个没有函数依赖关系的字段XYZ构成一张表,表内没有相同记录。
(2)违反第四范式的害处
插入异常:李四决定与A学校合作,但在犹豫合作教学哪个科目,是“数据结构”,还是“宇宙第一编程语言”?
此时,无法插入李四与A学校的任何记录【教学科目作为主属性不能为空】,李四犹豫半年,A学校财务部无法查到与李四的合作关系。
李四因此白白丢失半年薪水,虽然他掌握了“宇宙第一编程语言”,并且最终决定教学“宇宙第一编程语言”。
删除异常:如果李四停止与C学校合作,在违反第四范式的表中直接删除记录【红色部分】,那么,就可能因此丢失信息:李四可以教学“宇宙第一编程语言”。
张三决定放弃教学“地质学基础”,在违反第四范式的表中直接删除记录,那么,就可能因此丢失信息:张三与B校的合作关系。
更改异常:王五被A校高薪挖掘,改在A校教学,在违反第四范式的表中直接修改记录,需要修改多条记录(此例子为2条)。
(3)解决办法
将表拆分
将具有 多值依赖对称性的字段Y、Z拆开,分别与决定他们的X组成2个新表。如:(教师、学校);(教师、教学科目)
教师 | 学校 |
张三 | A学校 |
张三 | B校 |
李四 | B学校 |
李四 | C学校 |
李四 | D学校 |
王五 | D学校 |
教师 | 教学科目 |
张三 | 矿物学 |
张三 | 矿床学 |
张三 | 地质学基础 |
李四 | 数据结构 |
李四 | 宇宙第一编程语言 |
王五 | 体育 |
王五 | 定向越野 |
第四范式结合BCNF,就会让我们得出一个关系型数据库设计的终极奥义:尽量不要用两个以上的字段组合来当主键(即三个或三个以上)。如果他们之间没关系而完全独立,那么你踩中第四范式;如果他们之间有函数依赖关系,那么你踩中BCNF。如果非要这么做(超过两个字段),请保证他们之间至少有一一对应关系,而悄咪咪遵守BCNF和第四范式。用三个或三个以上字段当主键,虽然有的时候在语义上,他们不可能产生插入、修改和删除异常,但是数据库可能没办法保证每一步都遵守语义,那是人类理解的范畴。
6.第五范式
有大神说,第五范式处理的是无损连接问题,没啥意义,不学也罢。他还说,这个世界上,还有一种只存在于理论中的范式,叫域键范式(DKNF)。