1. 第二范式
第二范式要求,在满足第一范式的基础上,还要满足数据表里的每一条数据记录,都是可唯一标识的。而且所有非主键字段,都必须完全依赖主键,不能只依赖主键的一部分。如果知道主键的所有属性的值,就可以检索到任何元组的任何属性的任何值。(要求中的主键,其实可以扩展替换为候选键)。
1). 例1:
成绩表(学号,课程号,成绩)关系中,(学号,课程号)可以决定成绩,但学号不能决定成绩,课程号也不能决定成绩,所以“(学号,课程号)--> 成绩”就是完全依赖关系。
2). 例2:
比赛表player_game,里面包含球员编号,姓名,年龄,比赛编号,比赛时间和比赛场地等属性,这里候选键和主键都为(球员编号,比赛编号),我们可以通过候选键来决定如下关系。
(球员编号,比赛编号)--> (姓名,年龄,比赛时间,比赛场地,得分)
但这个数据表不满足第二范式,因为数据表的字段之间还存在如下的关系:
(球员编号)--> (姓名,年龄)
(比赛编号)--> (比赛时间,比赛场地)
对于非主属性来说,并非完全依赖候选键。这种情况下会产生问题。
为了避免出现上述的情况,我们可以把球员比赛表设计为下面的三张表。
表名 | 属性 |
球员player表 | 球员编号,姓名和年龄等属性 |
比赛game表 | 比赛编号,比赛时间和比赛场地等属性 |
球员比赛关系player_game表 | 球员编号,比赛编号和得分属性 |
这样的话,每张数据表都符合第二范式,也就避免了异常情况的情况。
- 1NF告诉我们字段属性需要是原子性的,而2NF告诉我们一张表就是一个独立的对象,一张表只表达一个意思。
- 2NF要求实体的属性完全依赖主关键字。如果存在不完全依赖,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。
2. 第三范式
第三范式是在第二范式的基础上,确保数据表中每一个非主键字段都和主键字段直接相关,也就是说,要求数据表中的所有非主键字段不能依赖于其他非主键字段,不存在传递依赖(即,不能存在非主属性A依赖于非主属性B,而非主属性B依赖于主键C的情况,即存在A->B->C的决定关系),通俗地讲,该规则的意思是所有非主键属性之间不能有依赖关系,必须相互独立。
这里的主键可以拓展为候选键。
举例1:
部门信息表:每个部门有部门编号,部门名称,部门简介等信息。
员工信息表:每个员工有员工编号,姓名,部门编号。列出部门编号后就不能将部门名称,部门简介等与部门有关的信息加入员工信息表中。
因为知道部门编号,就知道部门名称,部门简介,它们都是非主属性,且存在依赖关系。
第三范式不允许非主属性之间存在依赖关系。
符合3NF后的数据模型通俗的讲,2NF和3NF以这句话概括:每个非键属性依赖于键,依赖于整个键,并且除了键别无他物。
3. 小结
关于数据表的设计,有三个范式要遵循。
- 第一范式:确保每列保持原子性。数据库的每一列都是不可分割的原子数据项,不可再分的最小数据单元,而不能是集合,数组,记录等非原子数据项。
- 第二范式:确保每一列都和主键完全依赖。尤其是复合主键的情况下,非主键部分不应该依赖部分主键。
- 第三范式:确保每列都和主键列直接相关,而不是间接相关。
范式的优点:数据的标准化有助于 消除数据库中的数据冗余,3NF通常被认为在性能,扩展性和数据完整性方面达到最好的平衡。
范式的缺点:范式的使用,可能降低查询的效率。因为范式等级越高,设计出的数据表越来越多,越精细,数据的冗余度越低,进行数据查询的时候就可能需要关联多张表,这不但代价昂贵,也可能使一些索引策略无效。
范式只是提出了设计的标准,但实际设计数据表时,未必一定要符合这些标准。开发中,我们会为了性能和读取效率违反范式化的原则,通过增加少量冗余或重复的数据来提高数据库的性能,减少关联查询 ,join表的次数,实现空间换时间的目的。