关系数据库范式详解
这是我以前的一篇学习笔记,现补充修订之发表到这里。
关系数据库中,数据表是最基本的对象,表的好坏,直接关系到数据库的效率以及对数据库管理和维护,因此,开始建立数据库之前,用户须先对数据库中的数据表进行仔细的分析和设计。比如那些数据存放在一张表中、每个字段的名、字段属性的设计、一个数据库中包含几张表、与表之间的联系等。咋看起来,设计表似乎很容易,实际上要理解和如何将数据划分到不同的表,并不那么简单。本节介绍表的设计时需要遵守的规范,不遵守这些规范,表的设计难免出现问题,就极有可能会给后续开发和维护带来许多困难。
规范化过程的两个主要目的是:消除冗余数据(冗余数据指把相同的数据存储多次)和确保数据的依赖性处于有效状态(相关数据只存储在一个表里)。这两个目标的实现很有意义,因为能够减少数据库和表的空间消耗,并确保数据存储的一致性和逻辑性。
数据尽可能少地冗余,这意味着重复数据应该减少到最少。比如说,一个部门雇员的电话不应该被存储多次, 因为这里的电话号码是雇员的一个属性。如果存在过多的冗余数据,这就意味着要占用了更多的物理空间,同时也对数据的维护和一致性检查带来了问题,当这个员工的电话号码变化时,冗余数据会导致对多次更新动作,如果不幸被忽略了一些,那么就可能导致数据的不一致性。
关系数据库有六种范式(Normal form)。一般来说,数据库只需满足第三范式(3NF)就行了。
第一范式(1NF)
如果一个关系模式R的所有属性都是不可分的基本数据项,则称关系R是第一范式的模式。
等价说法:在一行中的每一列的值具有原子性,并且不能包含重复的数据列。
不满足第一范式的情况:
关系R ( name,address,phone)
----------------------------------------------------------------------------
name address phone
AA 山东某地 6220446, 6220524
BB 山东某市 6222666
----------------------------------------------------------------------------
说明,包含重复的数据列,phone可以再分。
要满足第一范式,可以修改为, 关系R ( name,address,phone1,phone2)
----------------------------------------------------------------------------
name address phone1 phone2
AA 山东某地 6220446 6220524
BB 山东某市 6222666
----------------------------------------------------------------------------
或将之改为:关系R ( name,address,phone)
----------------------------------------------------------------------------
name address phone
AA 山东某地 6220446
AA 山东某地 6220524
BB 山东某市 6222666
----------------------------------------------------------------------------
第二范式(2NF)
先说明几个相关概念。
什么是函数依赖(FD,Functional dependency):
设X和Y是关系R属性集的子集,若存在两个元组在X上的属性值相等, 则在Y上的属性值也相等, 则称(在关系R中)“X函数确定Y” 或 “Y函数依赖于X”,记作X→Y。
换一种说法,设X和Y是关系R属性集的子集,若对任意一个X的值有唯一的Y的值与之对应(即对任意X的值能唯一决定Y的值), 则称“X函数确定Y” 或 “Y函数依赖于X”,记作X→Y。
X称为这个函数依赖的决定因子(Determinant)。
需要注意:
1),X→Y只是确保对于X的任意一个取值,Y都有唯一的值与之对应 ,但反过来却不一定,即对于Y的任意一个取值,X可能有多个值与之对应 。
2)并不能总是可以从样本数据中判断函数依赖,可能没有任何样本数据或样本数据并不能恰当表示出数据间的依赖关系,因此需要依据实际情况判断。
3)设A 、B、C是关系模式R属性集的任意子集,有以下规则(rule):
若A→B,且B→C,则A→C。此为传递规则。
若A→(B,C),则A→B,A→C。此为分解规则。
若A→B,A→C,则A→(B,C)。此为组合规则。
等等。
关系模式R ( n,s,p),设它的一个关系样本值如下:
--------------------------------------------------------------------------------------------------------------
n s p
S1 20 p1
S2 10 p1
S2 10 p2
S3 20 p2
S3 20 p4
--------------------------------------------------------------------------------------------------------------
n→s (对于本例,只有这一个成立。如n→p等不成立。n→p不成立是因为存在n的一个值对应着p的多个值,如S2 对应着p1、p2)。
函数依赖实际是关系中两个属性集之间的约束。
什么是局部依赖和完全依赖:
对于依赖关系 W→A (A依赖于W,或者说W决定A),如果存在X归属于W,且X→A(A依赖于X),那么称W→A是局部依赖(也叫左部可约依赖),记作X —→P Y;否则称W→A是完全依赖(左部不可约依赖),记作X —→F Y。
第二范式定义:
如果关系模式R满足第一范式,且每个非主属性[注:属性有时又称为列,字段 ]完全依赖于键(key),则称R满足第二范式。所谓完全依赖是指不能存在仅依赖于键的一部分。
等价说法:非键列必须完全依赖整个键。或者说,不完全依赖于表中键的列都应移到另外一个表中。
何谓主属性、非主属性?主属性是构成键的属性,其他的为非主属性。
消除这种情况的办法是,将其分解成两个关系模式:一个由A属性集和Z属性集组成,主键是A;另一个由除去Z的属性集组成,外键是A,主键仍是W。
当键为单个列时,不会违反第二范式。
当键由多列组成时就可用此规则判别是否违反第二范式,第二范式的任务就是满足第一范式的前提下,消除了非主属性对键的部分函数依赖。
例、设关系模式R(S#,C#,Score,T#,TiTle),其中属性分别表示学生学号、选修课程编号、成绩、任课教师编号和教师职称。
R中有两个函数依赖,(S#,C#)→(T#,TiTle)和C#→(T#,TiTle),前一个是局部依赖,因此关系模式R不是2NF。将之分解为R1(S#,C#,Score)和R2(C#,T#,TiTle)。
第三范式(3NF)
先说明什么是传递依赖:
如果X→Y,Y→A,且Y\→X,A不是Y的子集,那么称X→A是传递依赖(A传递依赖于X)。
定义中之所以要加上条件Y\→X,是因为如果Y→X,则X←→Y,这实际上是A直接依赖于X,而不是传递函数了。
第三范式定义:
如果关系模式R是2NF,且每个非主属性[ 注:属性有时又称为列,字段] 都不传递依赖于R的键(key),那么称R满足第三范式。
等价说法:第三范式要求非键列互不依赖。或者说,数据库表中不包含(删除)已在其它表中已包含的非键字段[ 外键在多表中的重复出现例外]。
消除这种情况的办法是,将其分解成两个关系模式:一个由X属性集和A属性集组成,主键是X;另一个由除去A的属性集组成,外键是X,主键仍是W。
第三范式任务就是满足第二范式的前提下,消除了非主属性传递函数依赖于主键。
例、在上例中R1(S#,C#,Score)是2NF,而且也是3NF,但是R2(C#,T#,TiTle)是2NF,而且也不是3NF。因为有C#→T#和T#→TiTle。将R2(C#,T#,TiTle)分解成R21(T#,TiTle)和R22(C#,T#),R21和R22已是3NF。
再举一例,不满足第三范式的情况:
关系模式Sales ( CId,name,salesperson,region)是2NF模式,其中, CId:客户ID;name:名字;salesperson:推销员:region:区域。设它的一个关系样本值如下:
--------------------------------------------------------------------------------------------
CId name salesperson region
8023 安德森 史密斯 南部
9167 班克罗福特 希克斯 西部
7924 霍布斯 史密斯 南部
6837 塔克 赫尔南德斯 东部
8596 埃克斯利 希克斯 西部
7018 阿诺德 法奥布 北部
--------------------------------------------------------------------------------------------
说明:因为存在传递依赖CId→salesperson→region。
消除方法:分解关系模式Sales 为Sales1和Sperson:
----------------------------------------------------------------------
Sales1 ( CId,name,salesperson)
CId name salesperson
8023 安德森 史密斯
9167 班克罗福特 希克斯
7924 霍布斯 史密斯
6837 塔克 赫尔南德斯
8596 埃克斯利 希克斯
7018 阿诺德 法奥布
Sperson ( salesperson,region)
salesperson region
史密斯 南部
希克斯 西部
赫尔南德斯 东部
法奥布 北部
----------------------------------------------------------------------
Boyce-Codd范式(BCNF)
在3NF关系模式中并未排除主属性对键的传递依赖。
说明:这种情况和前一种情况的异同:1)不同点在于,只是属性A是键的一部分;2) 消除这种情况的办法和前一种情况一样,即将其分解成两个关系模式,一个由X属性集和A属性集组成,主键是X;另一个由除去A的属性集组成,外键是X,主键仍是W。
BCNF更进一步提高了约束,即同时排除了主属性对键的传递依赖。
什么是平凡函数依赖和非平凡函数依赖:
X→Y,但是(即Y是X的子集),则称X→Y为平凡的函数依赖。
X→Y, 但是(即Y不是X的子集),则称X→Y为非平凡的函数依赖。
等价的表述:平凡的函数依赖指左边是右边的超集的函数依赖;非平凡的函数依赖指左边不是右边的超集的函数依赖。
注意:
1)“平凡的(trivial)”含义指微不足道的,不重要的。值得关注的应是“非平凡的(nontrivial)”。
2)子集和真子集的区别:
A包含B,但A不等于B,B就是A的真子集,记为:B⊂A 或A⊃B
如果A包含B,A不等于或等于B,B都是A的子集记为:B⊆A或A⊇B
区别是, 真子集一定是子集 但是子集不一定是真子集。按范围来说子集大于或等于真子集。
例、R1 ( sno,cno,grade) 其中sno:学生学号;cno:课程编号;grade:成绩。
非平凡函数依赖: (sno, cno) → grade
平凡函数依赖: (sno, cno) → cno 、(sno, cno) → cno
Boyce-Codd范式(BCNF)定义:
关系模式R,如果对于每个非平凡的函数依赖X→Y,则X必含有R的键,那么该关系模式属于BCNF。
BCNF的条件有多种等价的表述,如:
关系模式R属于BCNF,当且仅当对每一个满足非平凡的函数依赖X→Y的R,X是R的超键。
由定义可知:属于BCNF关系模式,有两种情况1)关系模式中所有函数依赖是平凡的,2)若关系模式中含有非平凡的函数依赖,非平凡的函数依赖的左边(决定因素)必须含有R的键(注:“含有R的键”的意思等同“R的超键”, 超键是含有键的超集,不一定是真超集)。
BCNF是消除了所有属性的传递函数依赖。既检查非主属性,又检查主属性。当只检查非主属性时,就成了第三范式。
例、设有关系模式SSP(S#,SNAME,P#,QTY),其中属性分别表示供应商编号、供应商姓名、零件编号、发货数量。假定供应商姓名不会重名。它的候选键是(S#,P#)和(SNAME,P#)。
根据定义判断这个关系模式SSP属于3NF。但是它不属于BCNF,因为存在非平凡的函数依赖S# →SNAME和SNAME→S#(因为S# →SNAME和SNAME→S#的决定因素没有含有关系模式SSP的键)。可以将之分解为:
SS(S#,SNAME)和SP(S#, P#,QTY)
或者
SS(S#,SNAME)和SP(SNAME, P#,QTY)
需要注意的是,由于满足BCNF同时肯定满足约束程度低的范式,所以规范化并不一定非要从1NF到2NF到3NF到BCNF,一步一步进行。事实上,可以通过下列过程直接将一个关系模式分解成转化成BCNF。
- 识别每个函数依赖
- 识别出键(key)——候选键,常常是主键
- 识别出决定因素不是键(key)的函数依赖
- 用此函数依赖的所有列移出建立一个新关系模式
- 让此函数依赖的决定因素成为新关系模式的主键
- 并令此函数依赖的决定因素作为原关系模式的外键
4)如果存在多个这样的函数依赖,从包含列最多的那个函数依赖开始,重复3)直到函数依赖决定因素都是键
一般满足BCNF或3NF就可以避免许多问题。
数据库设计中心是如何设计数据的逻辑结构,关系数据库设计时,数据建模常用实现技术是实体/联系模型(E-R模型),在此基础上确定需要哪些关系模式(有些文献称为关系变量),以及关系模式中应含有哪些属性和关系模式之间的联系等。规范化主要用来验证设计结果——关系模式是否存在异常。
正确认识两种情况
在多表中出现的外键, 不属于数据冗余,这个观念必须记清。
其次,字段的派生出现,一般也是允许的。例:商品中的“单价、数量、金额”三个字段,“金额”就是由“单价”乘以“数量”派生出来的这是一种高级冗余(派生冗余),这种冗余的目的是为了提高处理速度。只有低级冗余才会增加数据的不一致性,因为同一数据,可能需要在多个表中多次录入。因此,应当防止低级冗余(重复性冗余)。
没有冗余的数据库设计可以做到。但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。如何执行规范化要由你自己来做决定,不过在决定之前,最好要全面了解各种范式以及没有执行相关范式的风险。
不同级别的规范化能防止不同类型的错误或潜在异常问题。另一方面,较高级别的规范化需要将表分解成较多的小的表,当需要它们时,重新联接这些小的表时也将变得更加困难和耗时。通常而言,3NF就可以将数据异常的几率降低到合理水平,也不至于增大过多的工作量。这需要较高的权衡策略和经验。
第四范式(4NF)
先说明几个相关概念。
什么是多值依赖(Multivalued Dependency):
设X、 Y和Z是关系模式属性集U的子集,并且Z=U-X-Y,当且仅当任一(X,Z)上的每个值对应一组Y的值,这组值仅仅决定于X值而与Z值无关,那么称作Y多值依赖于X(或X多值决定Y),记为:X→→Y。
注意,多值依赖决定因素与一个值的集合相关,多值依赖决定因素也不会是主键。
什么是平凡多值依赖和非平凡的多值依赖:
(设X、 Y和Z是关系模式属性集U的子集,Z=U-X-Y)
若X→→Y,而Z=φ,则称 X→→Y为平凡的多值依赖。φ代表空集。
若X→→Y,而Z≠φ,则称X→→Y为非平凡的多值依赖。
在关系模式R中,如果有X+Y+Z=U,对于任意<X,Z>的,都有Y与之对应,且Y只与X的值有关,与Z无关,就称Y多值依赖于X。也就是说对于任意的<X,Zi>,<X,Zj>,i<>j,都对应一个y 。
4NF中可能的多值依赖都是非平凡的多值依赖。
设有一个课程安排关系,如下表所示:
课程名称 | 任课教师 | 选用教材名称 |
高等数学 | T11 T12 T13 | B11 B12 |
数据结构 | T21 T22 T23 | B21 B22 B23 |
由此可知,具有如下语义:
⑴“高等数学”这门课程可以由3个教师担任,同时有两本教材可以选用。
⑵“数据结构”这门课程可以由3个教师担任,同时有3本教材可以选用。
关系模式CTB(Cn,Tn,Bn),其属性分别表示“课程名称”、“任课教师”和“教材名称”。上述情形样本值如下表所示:
关系CTB
Cn | Tn | Bn |
高等数学 | T11 | B11 |
高等数学 | T11 | B12 |
高等数学 | T12 | B11 |
高等数学 | T12 | B12 |
高等数学 | T13 | B11 |
高等数学 | T13 | B12 |
数据结构 | T21 | B21 |
数据结构 | T21 | B22 |
数据结构 | T21 | B23 |
数据结构 | T22 | B21 |
数据结构 | T22 | B22 |
数据结构 | T22 | B23 |
数据结构 | T23 | B21 |
数据结构 | T23 | B22 |
数据结构 | T23 | B23 |
很明显,这个关系表是数据高度冗余的。同时可知存在Cn→→Tn, Cn→→Bn。
第四范式(4NF)定义
设D是关系模式R上成立的函数依赖和多值函数依赖的集合,如果D中每个非平凡的多值函数依赖X→→Y,X都是R的超键(X包含R的键),那么R是4NF。
如果X→→Y,且X不是R的超键,那么任何包含X、Y,以及其它一个或多个属性的关系模式,都将存在修改异常问题,需要拆分要拆分成两个关系模式:一个由X属性集和Y属性集组成X;另一个由除去Y的属性集组成。
对于前面提到的关系模式CTB(Cn,Tn,Bn)惟一的侯选键是{Cn,Tn,Bn},并且没有非主属性,当然就没有非主属性对候选键的部分函数依赖和传递函数依赖,所以CTB满足BCNF。但在多值依赖Cn→→Tn和Cn→→Bn中的“Cn”不是键,所以CTB不属于4NF。对CTB进行分解,得到CTB1(Cn,Tn)和CTB2(Cn, Bn),样本值如下所示:
关系CTB1
Cn | Tn |
高等数学 | T11 |
高等数学 | T12 |
高等数学 | T13 |
数据结构 | T21 |
数据结构 | T22 |
数据结构 | T23 |
关系CTB2
Cn | Bn |
高等数学 | B11 |
高等数学 | B12 |
数据结构 | B21 |
数据结构 | B22 |
数据结构 | B23 |
在CTB1中,有Cn→→Tn,不存在非平凡多值依赖,所以CTB1属于4NF;同理,CTB2也属于4NF。
再举一例:
设关系模式R(Course,Student,Pre-course),其中属性分别表示课程、选修此课程的学生、此课程的先修课程。键是(Course,Student,Pre-course),显然,Course和Student之间是1:N联系,Course和Pre-course之间也是1:N联系。样本值如下:
Course | Student | Pre-course |
C4 | S1 | C1 |
C4 | S1 | C2 |
C4 | S1 | C3 |
C4 | S2 | C1 |
C4 | S2 | C2 |
C4 | S2 | C3 |
键是全部属性。可以判断 R已符合BCNF。
但是存在非平凡的多值依赖Course→→Student和Course→→Pre-course,并且左部都未包含键,因此不符合4NF。分解成R1(Course,Student)和R2(Student,Pre-course),R1和R2都符合4NF。
第五范式(5NF)
设关系模式SPJ(SNO,PNO,JNO),其属性分别表示供应商、零件和项目,主键由全部属性(SNO,PNO,JNO)构成。它显然达到了4NF。
关系模式SPJ的一个实例如下表:
SNO | PNO | JNO |
S1 | P1 | J1 |
S1 | P1 | J2 |
S1 | P2 | J1 |
S2 | P1 | J1 |
SPJ分别在SP、PJ、SJ上的投影如下:
SP、
SNO | PNO |
S1 | P1 |
S1 | P2 |
S2 | P1 |
PJ
PNO | JNO |
P1 | J1 |
P1 | J2 |
P2 | J1 |
SJ
SNO | JNO |
S1 | J1 |
S1 | J2 |
S2 | J1 |
SPJ分别在SP、PJ、SJ上的投影如下:SP、PJ、SJ两两自然连接(join , 联接)的结果如下:
SPJ——SP、PJ自然连接
SNO | PNO | JNO |
S1 | P1 | J1 |
S1 | P1 | J2 |
S1 | P2 | J1 |
S2 | P1 | J1 |
S2 | P1 | J2 |
SPJ——PJ、SJ自然连接
SNO | PNO | JNO |
S1 | P1 | J1 |
S1 | P1 | J2 |
S1 | P2 | J1 |
S2 | P1 | J1 |
S2 | P2 | J1 |
SPJ——SP、SJ自然连接
SNO | PNO | JNO |
S1 | P1 | J1 |
S1 | P1 | J2 |
S1 | P2 | J1 |
S1 | P2 | J2 |
S2 | P2 | J1 |
从这个实例可以看出,关系SPJ,分解为其中两个属性的关系后,无论哪两个投影自然连接后都不是原来的关系,因此不是无损失连接。但是我们却发现,对于两两自然连接的结果,如果再与第三个关系连接(例如(1)与SJ连接),又能够得到原来的SPJ,从而达到无损失连接。
在这个问题中SPJ依赖于3个投影SP、PJ、SJ的连接。
定义 关系模式R(U)中,U是全体属性集,X,Y,…,Z是U的子集,当且仅当R是由其在X,Y,…,Z上投影的自然连接组成时,称R满足对X,Y,…,Z的连接依赖(Join Dependency)。记为 *(X,Y,…,Z)。
等价定义,设R1、R2、…、Rn是关系模式R的属性集的子集,当且仅当R的任何的合法的值都与它在A、B、…、X上的投影的连接(join)等价,就称R满足连接依赖,记为
*(R1,R2,…,Rn)
什么是平凡的连接依赖和非平凡的连接依赖:
如果R满足连接依赖*(R1,R2,…,Rn)中某个Ri等同R,那么*(R1,R2,…,Rn)是平凡的连接依赖。
如果R满足连接依赖*(R1,R2,…,Rn)中没有任一个Ri等同R,那么*(R1,R2,…,Rn)是非平凡的连接依赖。
定义 关于模式R中,当且仅当R中每个连接依赖均为R的候选码所蕴涵时,称R属于5NF。
等价定义,如果关系模式R的每一个非平凡的连接依赖都被R的超码所蕴涵时,那么R属于5NF。
说明:“R中每个连接依赖均为R的候选码蕴涵”是指对于关系R,在连接时其连接属性都是R的候选码。
判断一个关系模式是否为5NF,需要找出该关系模式的全部连接依赖,再判断每个连接时是否按候选键进行。(要找出关系模式的全部连接依赖这是非常困难的事情,现实应用有限。)
现在接着上面例子分析:
关系模式SPJ依赖于3个投影产生的三个关系模式SP(SNO,PNO)、PJ(PNO,JNO)、SJ(SNO, JNO)的连接,因此SPJ的连接依赖是可记为*((SNO,PNO),(PNO,JNO),(SNO,JNO)),也可记为 *(SP,PJ,SJ),后者用关系模式的名代表它的属性集合。
SPJ不属于5NF。因为:
从5NF第一个定义的角度看, SPJ依赖于3个投影产生的三个关系模式SP、PJ、SJ的连接——但连接不是按候选键进行的——SPJ的键是(SNO,PNO,JNO),SP的键是(SNO,PNO),PJ的键是(PNO,JNO),SJ的键是(SNO, JNO),所以判断SPJ不属于5NF。
从5NF第二个定义的角度看,因为:连接依赖是非平凡的——SP,PJ,SJ没有一个属性和SPJ属性形同,这个非平凡的连接依赖不被R的超码所蕴涵——SP、PJ、SJ的连接时不是按候选键进行的。
因此,需要分解SP、PJ、SJ三个关于模式。
SP、PJ、SJ均属于5NF。
判断一个关系模式是否属于5NF,若能够确定它的候选码和所有的连接依赖,就可以判断其是否属于5NF。然而找出所有连接依赖是比较困难的,因此确定一个关系模式是否属于5NF的问题,比判别其是否属于4NF的难度要大得多,因为将涉及到更多的知识,在这里就不再深入探讨了。属于5NF的模式一定属于4NF。
小结
规范的实质就是概念的单一化,即一个关系模式描述一个实体或实体间的一种联系。
规范化目的是使结构更合理,消除存储异常,使数据冗余尽量小。便于插入、删除和更新。
一个关系模式接着分解可以得到不同关系模式集合,也就是说分解方法不是惟一的。其根本目标是节省存储空问,避免数据不一致性,提高对关系的操作效率,同时满足应用需求。一般而言,到第三范式(3NF)就可以了。范式越高意味着表的划分更细,一个数据库中需要的表也就越多,用户不得不将原本相关联的数据分摊到多个表中。当用户同时需要这些数据时只能采用连接表的形式将数据重新合并在一起。同时把多个表联接在一起的花费是巨大的,尤其是当需要连接的两张或者多张表数据非常庞大的时候,表连接操作几乎是一个噩梦,这严重地降低了系统运行性能。