数据库_范式那些事
作者:互联网
首先,来弄清楚几亿个概念。
数据依赖:主要类型分为函数依赖(Functional Dependency,FD)和多值依赖(Multivalued Dependency)
函数依赖:
给定一个属性的值,另一个属性的值也会确定。如同数学中的函数,输入一个x值得到一个确定的f(x),所以称为函数依赖。
举个例子:一个属性组F{Sno->Sdept,Sdept->Mname,(Sno,Cname)->Grade}
在这个关系中,Sdept依赖于Sno,Mname依赖于Sdept,Grade依赖于Sno和Cname,记作Sno->Sdept,Sdept->Mname,(Sno,Cname)->Grade。
完全函数依赖:
在一张表中,若 X→Y,且对于 X 的任何一个真子集(假如属性组 X 包含超过一个属性的话),X→Y 不成立,那么我们称 Y 对于 X 完全函数依赖,记作 X F→ Y(F应该是在箭头上面)。长下面这样子,别人网页偷的:
简单的解释一下就是如果X中包含1个以上的属性,如上面提到的属性组F中的(Sno,Cname)->Grade,这两个属性放在一起才能唯一确定一个Grade,这就称为Grade完全依赖于(Sno,Cname)。
部分函数依赖:
与完全函数依赖类似的定义,如果X→Y,但是不完全依赖于X,即X的子集也可以推出Y,那么就称为Y部分函数依赖于X。记做X P→ Y(P应该是在箭头上面),写做:
简单的解释一下,还是上面的那个例子。如果F中的Sno代表的同学只有一门课,那么就算是只有他的学号Sno也可以确定他的成绩Grade,Cname在这个依赖中没有起到作用,这就称为部分函数依赖。
传递函数依赖:
在一个关系模式R(U)中,如果X→Y,Y→Z.(X不依赖于Y,且Y不属于X),则成Z传递依赖于X。
如果Y→X,即X<->Y,则Z直接依赖于X。记作:
说人话就是x->y,y->z,那么z就是传递依赖于x,中间用y传递了一下。不举例子了,后面具体用途的时候在细说。
平凡函数依赖与非平凡函数依赖:
设一个关系为R(U),X和Y为属性集U上的子集,若X→Y且X不包含Y,则称X→Y为非平凡函数依赖。
若Y包含于X,则称X→Y称为平凡函数依赖。
说人话就是平凡函数依赖说的是X的子集一定是依赖于X的,非平凡函数依赖就是X外的属性依赖于X。
平凡的没什么研究价值,只要是依赖就必然成立,所以学习的重点在于非平凡函数依赖。
码:
细分可以分为主码、候选码、码。关系是:主码 候选码 码。
先假设一个场景,在{a,b,c,d},知道a就能确定a、b、c、d的值,知道c、d可以确定a、b、c、d的值。
1.码:可以确定一个元组所有信息的属性名或者属性名组。
在上面的场景中,{a}和{c,d}是码,他们可以唯一确定其他属性的值。
2.候选码:候选码的真子集中不存在码,候选码可以有很多个。
还是上面的例子,{a}、{c,d}是候选码,他们的子集中不存在码,如果是{a,b},{a,b,c}等则不属于候选码,因为他们的子集都有{a},{a}是码,所以含有码的集合都不属于候选码。
3.主码:也称为主键,就是任意一个候选码。
在上面的例子中,{a}和{c,d}都可以是主码。
码还有一点东西,不如上面三个重要,还是讲一下。
主属性和非主属性:包含在任意一个候选码中的属性为主属性,不包含在任意一个候选码中的就是非主属性。
全码:整个属性组都是码,则称之为全码。
终于把概念弄清楚了,下面是规范化的具体内容。
规范化:指为了控制由于冗余等带来的问题而要求关系模式满足一定条件的范型,可以通过模式分解来达到,这一过程称之为规范化。规范化的目的是改造不好的关系模式。
范式:关系数据库中的关系模式要满足一定要求,满足不同程度要求的称为不同的范式,第几范式表示关系的某种级别。数据库范式分为1NF,2NF,3NF,BCNF,4NF,5NF,高级范式必定符合低一级范式的要求,比如2NF的关系模式一定符合1NF。
第一范式(1NF):
定义:(1NF, Normal Form) 如果一个关系模式R中的每个属性A的域值都是原子的,即属性值是不可再分的,则关系模式R属于第一范式,简记为R ∈ 1NF。若数据库模式R中的每个关系模式都是1NF,数据库模式 R∈1NF。
简单来说,1NF中的所有属性都是不可再分的,如下图所示,学生S仍可以细分为学号Sno和姓名Sname,所以不满足1NF。
学生S | 性别Ssex | 年龄Sage | 专业Sdept | |
学号Sno | 姓名Sname | |||
S1 | 张三 | 男 | 20 | 计算机系 |
将表格改成以下形式,即可满足1NF:
学号Sno | 姓名Sname | 性别Ssex | 年龄Sage | 专业Sdept |
S1 | 张三 | 男 | 20 | 计算机系 |
1NF是所有关系型数据库的最基本要求,如果数据表的设计不满足1NF,那么操作一定是不能成功的。同样的,已经存在于数据库中的表也一定是满足1NF的。
但是,仅符合1NF的设计,存在数据冗余过大,插入异常,删除异常,修改异常的问题,如:
关系模式SLC(Sno,Sdept,Sloc,Cno,Grade),Sloc为学生住所。假设同一个系的学生住在同一个地方。函数依赖包括:(Sno,Cno) F->Grade、Sno->Sdept、(Sno,Cno) P->Sdept、Sno->Sloc、(Sno,Cno) P->Sloc、Sdept->Sloc。看着很恶心,画成图:
好看多了,但还是看着很烦。
可以看出,主码为(Sno,Cno)。下面将简单介绍一下几个异常,以便引出第二范式。
1.插入异常:如果Sno=1,Sdept=IS,Sloc=N,但是该学生未选课,因为课程号为主属性,主属性不能为空,所以改条信息无法插入表SLC中,这与现实是不符的。
2.删除异常:如果一个大四学生只有一门课,还是选修课,他上了一节之后想躺宿舍摸鱼,所以他要退课,但是由于课程号是主属性,如果他退课的话课程号属性中没有值,这条操作无法完成,除非删除这个学生的整个元组。就想退个课结果不小心退学了,太惨了。
3.数据冗余度大:还是那个学生,他选了8门课来凑学分,在数据库中他的信息,Sdept,Sloc等无关信息需要重复8次,占用储存空间。
4.修改复杂:因为一个系的人都挤在一起,如果该学生要转系,可能不仅要改Sdept,还要改Sloc。假设他选了8门课,那么他转个系就得改8条数据,很烦。
由以上几个例子,可以发现1NF只是能用而已,并不是一个好的范式,当人数多了之后浪费的资源是非常吓人的,由此引出了第二范式。
第二范式(2NF):
定义:若关系模式R属于1NF,且每一个非主属性都完全函数依赖于R的码,则R属于2NF。
2NF和1NF的区别就是所有的非主属性都可以由码来确定而不是只由码的一部分确定。还是上文的SLC吧,现成的不用白不用。
问题的根源在于Sdept、Sloc存在部分函数依赖,Sdept可以由Sno确定,Sloc更离谱我都懒得写,这些奇怪的关系导致我们对数据做修改的时候很费劲,就像是桌子上的电线一样缠在一起,抽一根带十根,想想血压就高了。解决的方法也很简单,把线分开就是了,对应到我们的内容中就是:投影分解法。把SLC分解为两个关系模式以消除部分函数依赖就好了,说人话就是把一张复杂的表拆成两张表。
SC(Sno,Cno,Grade)和SL(Sno,Sdept,Sloc),然后上图:
虽然还是挺屎的,但是比之前好看了很多(自欺欺人,我一眼都不想看)。
SC的码是(Sno,Cno),SL的码是Sno,这样就消解了所有的部分函数依赖。只剩下了完全函数依赖,来一张图解释一下:
这样看来,就没有非主属性对码的部分函数依赖了。不过Sloc对Sdept还是存在函数依赖,这是第二范式管不到的地方,不过相对于第一范式已经做出了非常大的改进,下面来具体分析一下。
1.插入异常:学生选课和学生基本信息分别在两个表中,所以即使没有选课的学生也可以加入SL。
2.删除异常:删除一个学生的选课记录只影响SC,对SL没有影响,大四老哥不用退学了,好耶!
3.数据冗余度大:选课跟基本信息不在一张表里,重复的都是必要数据,大大降低了数据冗余。
4.修改复杂:数据都不怎么冗余了,修改操作自然也随之减少。
但是!划重点,追求进取的人类永远不会停止进步的步伐。
刚才其实也提到了,SL中仍存在着对于我们简化关系结构有障碍的关系,即Sloc对于Sdept的函数依赖,这个关系我们是不想要的,他看上去很多余,明明已经可以通过Sno确定Sloc,可是Sloc偏偏还和Sdept有不得不说的关系,这个关系也导致SL存在一些问题。
1.插入异常:一个系刚刚成立,还没有学生,那么码Sno就没有数据,这个系就没了,系长哭泣。
2.删除异常:某系决定暂停招生一段时间,把最后一批学生送走时候,删除学生数据,Sno又空了,这个系又没了,系长又哭了。
3.数据冗余大:一个系的所有学生都住在一起,可是Sloc这个属性却每个学生重复一次。
4.修改复杂:同上,Sloc重复的多,如果该系调整住址位置,修改的也多。
标签:Sdept,范式,Sno,数据库,那些,1NF,依赖,Sloc,属性 来源: https://www.cnblogs.com/m1nercy/p/14645059.html