概览
一、基本概念
1.超键
在一个关系中,能够唯一标志一个元组的属性集合被称为超键(Super Key),超键可以由单个或多个属性构成(可以为单列键也可以为复合键)。
2.候选键
也叫候选码(Candidate Key),它是一个属性集合,由关系中一个或多个属性组成,它要满足以下条件:
- 唯一性特性: 能够唯一地标志数据库表中的一行记录(必须为
超键
); - 最小特性:其真子集不能够唯一区别数据库表中的一行记录(也叫
最小超键
)。
一个关系中可以有多个候选键。考虑到主键的定义,我们也可以说候选键就是能被选为主键的属性或属性组。
2.主键
也叫主关键字,或主码(Primary Key)。如果一个关系中有多个候选键,那么可以从中选取一个候选键作为主键。在一个关系中只能有一个主键,而且主键的值不能为空。在关系表中它是可选的,主键被设置时,数据库会创建主键索引。
3.主属性与非主属性
包含在任一候选键中的属性,叫做主属性(Primary Attribute),任何不包含在候选键中的属性称为非主属性(Nonprime Attribute),也叫非码属性(Nonkey Attribute)。
针对上述提及的概念,我们以下面这个关系作为示例来讲解一下:
学生成绩表(学号,姓名,身份证号,课程名,得分)
我们可以知道:
- {学生,课程名}、{身份证号,课程名}都是超键,也都是候选键;
- {学生,课程名,姓名}是超键,但它不是候选键;
- “学生”、“身份证号”、“课程名” 都是主属性,“姓名”、“得分” 是非主属性
注意:上面这个表结构其实存在数据的冗余,不符合2NF
4. 函数依赖
-
数据依赖,在计算机科学中,数据依赖是指一种状态,当程序结构导致数据引用之前处理过的数据时的状态。其中最重要的是函数依赖和多值依赖;
-
函数依赖,设X,Y是关系R的两个属性集合,当任何时刻R中的任意两个元组中的X属性值相同时,则它们的Y属性值也相同,则称X函数决定Y,或Y函数依赖于X。比如关系
学生表(学号,姓名)
中,确定了学生的(学号)
也就确定了学生的(姓名)
,所以存在(姓名)
对(学号)
的函数依赖,表示为(学号)->(姓名)
; -
平凡函数依赖,当关系中属性集合Y是属性集合X的子集时(Y⊆X),存在函数依赖X→Y,即一组属性函数决定它的所有子集,这种函数依赖称为平凡函数依赖。比如关系
学生表(学号,班级)
,其中(学号,班级)->(学号)
,(学号,班级)->(班级)
都属于平凡函数依赖; -
非平凡函数依赖,当关系中属性集合Y不是属性集合X的子集时,存在函数依赖X→Y,则称这种函数依赖为非平凡函数依赖。比如关系
学生表(学号,姓名,寝室)
,(学号)->(姓名,寝室)
属于非平凡函数依赖; -
完全函数依赖,设X,Y是关系R的两个属性集合,X’是X的真子集,存在X→Y,但对每一个X’都有X’!→Y,则称Y完全函数依赖于X。比如关系
学生-课程表(学号,课程,得分)
,由于(学号,课程)->(得分)
但是(学号)-\->(得分)
且(课程)-\->(得分)
,所以(学号,课程)->(得分)
是完全函数依赖; -
部分函数依赖,设X,Y是关系R的两个属性集合,存在X→Y,若X’是X的真子集,存在X’→Y,则称Y部分函数依赖于X。比如关系
学生表(学号,身份证号,班级)
,由于(学号,身份证号)->(班级)
但是同时有(学号)->(班级)
、(身份证号)->(班级)
,所以(学号,身份证号)->(班级)
是部分函数依赖; -
传递函数依赖,设X,Y,Z是关系R中互不相同的属性集合,存在X→Y(Y !→X),Y→Z,则称Z传递函数依赖于X。比如关系
学生表(学号,班级,班主任)
,由于(学号)->(班级)
但是同时有(班级)-\->(学号)
且(班级)->(班主任)
,所以(学号)->(班主任)
是传递函数依赖;
函数依赖的理解属于关系理论的范畴,所以比较复杂和枯燥,但是对于后续范式的理解会有很大的助益,可以参考例子加深理解!
二、数据库范式
关系数据库中的关系必须满足一定的要求,即满足不同的范式(Normal Form)。范式是指符合某一种级别的关系模式的集合。满足适合的范式,能够帮助降低数据库的冗余,设计合理的数据库表结构。如今,关系型数据库一共有六种范式,各类范式要求依次递增,越高的范式数据库冗余越小。一般来说,数据库只需满足第三范式(3NF)就行了。
三、第一范式(1NF)
要求数据库表中的字段都是单一属性的,即属性应该是不可再分的。这是关系型数据库的基本要求。比如说属性地址
,可以继续拆分成多个属性省
、市
、镇
、街道
、门牌号
…仅满足第一范式的关系会存在大量的数据冗余,而且还会带来各种异常。
四、第二范式(2NF)
在第一范式的基础上,消除非主属性对候选键的部分依赖
。对于候选键只有一个属性的数据库表,其一定符合2NF
。比如关系如下:
学生-课程表(学号,姓名,性别,课程名,学分)
可知存在如下函数依赖:
- (学号,课程名)->(姓名,性别,学分)
- (学号)->(姓名,性别)
- (课程名)->(学分)
五个属性均不可再分,满足1NF
,由2,3可知存在分主属性对候选键((学号,课程名)
)的的部分依赖,所以上述表结构不满足2NF
,我们可以改造成以下三个表来满足2NF
:
- 学生表(学号,姓名,性别)
- 课程表(课程号,课程名,学分)
- 学生-课程表(学号,课程号)
五、第三范式(3NF)
在第二范式的基础上,消除非主属性对候选键的传递依赖
。比如关系如下:
学生表(学号,姓名,班级名,班主任)
可知存在如下依赖:
- (学号)->(姓名,班级名,班主任)
- (学号)->(班级名)
- (班级名)->(班主任)
因为主键是单列键,显然,满足2NF
,又由2,3可知存在(学号)->(班主任)
的传递依赖,所以不满足3NF
,可以改造为如下两个表使之符合3NF
:
- 学生表(学号,姓名,班级ID)
- 班级表(班级ID,班级名,班主任)
六、巴斯-科德范式(BCNF)
在满足第三范式的基础上,消除主属性对于候选键的部分函数依赖
与传递函数依赖
。这里参考了知乎里刘慰老师的回答。比如有如下关系:
仓库(仓库名,管理员,物品名,数量)(仓库指定由唯一管理员管理,管理员管理唯一仓库)
可知存在如下依赖:
- (仓库名,物品名)->(数量)
- (管理员,物品名)->(数量)
- (管理员)->(仓库名)
- (仓库名)->(管理员)
可知,这里只有一个非主属性,即“数量”,且不存在非主属性对两个候选键的部分与传递函数依赖。所以以上表关系满足3NF
。但存在着主属性对两个候选键的部分函数依赖,这会导致插入异常、删除异常、修改异常的存在,比如:
- 插入异常,不能插入一个空仓库(作为主属性的“物品名”不能为空);
- 删除异常,删除某个仓库内所有物品后,会一并将仓库的管理员信息删除;
- 修改异常,修改仓库的管理员信息,不得不进行批量修改,同理修改物品名、仓库名时也不得不批量修改。
可以改造如下两个表结构,使之符合BCNF
:
- 仓库(仓库名,管理员)
- 仓储(仓库名,物品名,数量)
推荐同学去看一看刘慰老师的回答,他的回答说明了范式应用对于设计表结构的具体好处
七、第四范式(4NF)
在BC范式的基础上,消除属性间非平凡且非函数依赖的多值依赖
,这里提到的多值依赖要与前面函数依赖的概念相区分,它们两个的概念完全不同。多值依赖表示属性间的一种依赖关系,如有属性X 、Y 、Z,对于X 的每个值,Y 有一个值集,Z有一个值集,并且Y 的值集和Z的值集彼此独立。比如如下关系:
课程表(课程名,修读该课程的学生,教授该课程的教师)
上述关系满足BCNF
,且可知一个课程对应N个学生的同时对应N个教师,且学生与教师是独立的,故不满足4NF,可以改造为如下的两个表结构,使之符合4NF:
- 学生-课程表(课程名,修读该课程的学生)
- 教师-课程表(课程名,教授该课程的教师)
八、第五范式(5NF)
在第四范式的基础上,消除关系中的所有冗余。5NF
避免了所有的数据冗余,节省了存储空间,同时保持了数据的一致性,但是也付出了效率上的代价。实际应用中,数据库适当的冗余其实有助于提高查询的效率,减少过多的表连接操作,所以5NF
的应用少之又少。为了帮助理解还是举个栗子吧:
选修课表(学生,课程,教师)(多个老师可以同时教授同一门选修课,多个学生能选修同一门选修课)
可知(学生,课程,教师)
就是唯一一个候选键,所有属性都是主属性,且不满足属性间的多值依赖,故满足4NF,但是存在大量冗余,可以改造为以下三个表结构,使之符合5NF
:
- 学生-课程表(学生,课程)
- 课程-教师表(课程,教师)
- 学生-教师表(学生,教师)
九、资料参考
- 百度百科
- 知乎 – 如何理解关系型数据库的常见设计范式?
- BCNF范式、第四范式和第五范式
- 郑鲁腾,杨寸月.4NF(第四范式)在实际中的应用研究[J].软件导刊,2009,8(05):49-50.
- 王丽华.关系数据库范式及应用[J].内江科技,2008(07):117-118.
十、勘误表
- 2020/03/24 第一次编辑
- 2020/04/10 更改标题,标题党走起