「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」。
数据库范式是数据库原理的重要知识点,然而数据库范式的语言描述让人十分难以理解,本文将通过数据表的实例,帮助理解数据库范式。
基本概念
在设计关系型数据库时,需要遵从不同的规范要求,以设计出合理的关系型数据库。这些不同的规范要求就被称为不同的范式。
数据库范式最主要目的是为了消除重复数据,减少数据冗余,更好地组织数据库内的数据,让磁盘空间得到更有效的利用。但是范式会使查询变得相当复杂,在查询时需要更多的连接,一些复合索引的列由于范式化的需要被分割到不同的表中,导致索引策略不佳。
范式的描述中涉及一些名词,它们的解释如下:
- 候选码:某些属性的组合可以在一个实体集中唯一地标识一个实体。如果对于某几个属性的组合,它们的任意真子集都不能唯一地标识一个实体,那么这样的最小组合称为候选码。
- 主码(主键):从候选码中挑的一个属性最少的组合
- 主属性:一个属性只要在任何一个候选码中出现过,这个属性就是主属性
- 非主属性:与主属性相反,没有在任何候选码中出现过的属性,是非主属性
第一范式
所有的域都应该是原子性的,即数据库表的每一列都是不可分割的原子数据项,而不能是集合、数组、记录等非原子数据项
第一范式比较好理解,类比编程语言,数据库所有的列都应该是基本类型,如整型、字符串等,而不能是符合类型,如列表、字典等。
比如现在有一张学生表,每个学生的联系方式有两种:手机号码和电子邮箱,那么符合第一范式的表,不应该设计为 学生(学号,姓名,联系方式)
,然后在联系方式列保存一个保存了手机号码和邮箱的列表,因为这样联系方式列就不是不可分割的原子项目了,而应该设计为:学生(学号,姓名,手机,邮箱)
。
第二范式
符合第一范式,并且非主属性完全依赖于候选码
第二范式是在第一范式的基础上,要求属性完全依赖于主键。所有单关键字的数据库表都符合第二范式,因为不可能存在组合关键字。
比如现在有一张选课表:选课关系表(学号,课程号,成绩,学分)
。在这张表中,主键为 (学号,课程号)
。而属性学分
只与课程号
相关,即属性部分依赖于主键。所以为了满足第二范式,需要对这张表进行拆分,拆分后的表为:选课关系表(学号,课程号,成绩)、课程表(课程号,学分)
第三范式
符合第一范式,并且每个非主属性既不部分依赖于码也不传递依赖于码
第三范式在第二范式基础上,消除了传递依赖
比如现在有一张学生表: 学生(学号,姓名,年龄,所在学院,学院地点)
。这张表的主键为 学号
,为单关键字因此符合第二范式。但是根据学号
可以知道学生所在学院
,根据所在学院
可以知道学院地点
,即非主属性传递依赖于主属性,因此不符合第三范式。为了满足第二范式,需要对这张表进行拆分,拆分后的表为:学生(学号,姓名,年龄,所在学院)、学院(学院名,学院地点)
。
BC 范式
符合第一范式,且主键的任何一个真子集都不能决定于主属性
BC 范式在第三范式基础上,消除对主键子集的依赖
比如现在有仓库管理表 仓库管理(仓库号,存储物品号,管理员号,数量)
,其中,每个管理员管理一个仓库,每个仓库有唯一一个管理员,所以,该表的候选码可以为 (仓库号,存储物品号)
也可以为 (管理员号,存储物品号)
。不管选择哪个作为候选码,数量
都完全依赖于候选码,所以符合第三范式。从候选码中可以得出,该表的主属性有 仓库号,存储物品号,管理员号
,由于管理员号
依赖于仓库号
(同样的,仓库号
也依赖于管理员号
),即主键的真子集决定于主属性,所以不符合 BC 范式。为了满足 BC 范式,这张表要给拆分为 仓库管理(仓库号,管理员号)、仓库表(仓库号,存储物品号,数量)
。