数据库表的设计(三大范式)
1. 范式
1.1 范式的概念
范式从本质上讲是一种理论体系、理论框架。在该体系框架之内的该范式的理论、法则、定律都被人们普遍接受。
1.2 范式的分类
目前关系型数据库有六种常见范式,按照范式级别,从低到高分别是:
- 第一范式(1NF)
- 第二范式(2NF)
- 第三范式(3NF)
- 巴斯-科德范式(BCNF)
- 第四范式(4NF)
- 第五范式(5NF,又称完美范式)。
数据库的范式设计越高阶,冗余度就越低,同时高阶的范式一定符合低阶范式的要求,满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。
一般来说,在关系型数据库设计中,最高也就遵循到BCNF,普遍还是3NF。但也不绝对,有时候为了提高某些查询性能,我们还需要破坏范式规则,也就是反规范化。
1.3 键和相关属性的概念
- 超键:能唯一标识元组的属性集叫做超键(主键、主键+任意字段、任何组合能唯一的能标识这一行的就是超键)。
- 候选键:如果超键不包括多余的属性,那么这个超键就是候选键(最小的超键,能唯一标识一行数据的字段)。
- 主键:用户可以从候选键中选择一个作为主键。
- 外键:如果数据表R1中的某属性集不是R1的主键,而是另一个数据表R2的主键,那么这个属性集就是数据表R1的外键。
- 主属性:包含在任一候选键中的属性称为主属性(候选键涉及到的属性)。
- 非主属性:与主属性相对,指的是不包含在任何一个候选键中的属性(候选键不涉及到的属性)。
1.4 举例说明
咱们创建简单的两个表,说明一下各个键!
表1 :学生表(学号 身份证号 性别 年龄 身高 体重 宿舍号)
表2 :宿舍表(宿舍号 楼号)
-
超键:只要含有“学号”或者“身份证号”两个属性的集合就叫超键,例如R1(学号 性别)、R2(身份证号 身高)、R3(学号 身份证号)等等都可以称为超键!
-
候选键:不含有多余的属性的超键,比如(学号)、(身份证号)都是候选键,又比如R1中学号这一个属性就可以唯一标识元组了,而有没有性别这一属性对是否唯一标识元组没有任何的影响!
-
主键:就是用户从很多候选键选出来的一个键就是主键,比如你要求学号是主键,那么身份证号就不可以是主键了!
-
外键:宿舍号就是学生信息表的外键
-
主属性:(学号)、(身份证号)都是候选键,那么学号是主属性,身份证号也是主属性。
-
非主属性:(学号)、(身份证号)都是候选键,那么除了学号和身份证号都是非主属性。
2. 第一范式
2.1 定义
数据库表中的所有属性都不可再分,即数据项不可分。
2.2 理解
第一范式强调数据表的原子性,是其他范式的基础。如下图所示数据库就不符合第一范式:
上表将商品这一数据项又划分为名称和数量两个数据项,故不符合第一范式关系。改正之后如下图所示:
上表就符合第一范式关系。
事实上,任何的DBMS都会满足第一范式的要求,不会将字段进行拆分。
3. 第二范式
3.1 定义
若某关系R属于第一范式,且每一个非主属性完全依赖于任何一个候选码,则关系R属于第二范式。
3.2 理解
通俗理解就是任意一个字段都只依赖表中的同一个字段。
举例:
比如有两个主键,如果存在一个属性,它只依赖于其中一个主键,而不依赖另一个主键,出现这种情况,就是不符合第二范式。
- 依赖:在数据表中,属性(属性组)X确定的情况下,能完全退出来属性Y完全依赖于X。
- 完全依赖:完全依赖是针对于属性组来说,当一组属性X能推出来Y的时候就说Y完全依赖于X。
- 部分依赖:一组属性X中的其中一个或几个属性能推出Y就说Y部分依赖于X。
4. 第三范式
4.1 定义
- 首先,要满足第三范式(3NF)必须先满足第二范式(2NF)。
- 满足所有非主键属性都只和候选键有相关性,也就是说非主键属性之间应该是独立无关的。
4.2 理解
- 不能存在非主属性A依赖于非主属性B,非主属性B依赖于主键C的情况,即存在“A→B→C”的决定关系。
- 通俗地讲,就是所有非主键属性之间不能有依赖关系,必须相互独立。
5. 范式的优缺点
5.1 优点
数据的标准化有助于`消除数据库中的数据冗余``,第三范式(3NF)通常被认为在性能、扩展性和数据完整性方面达到了最好的平衡。
5.2 缺点
范式的使用,可能降低查询的效率。因为范式等级越高,设计出来的数据表就越多、越精细,数据的冗余度就越低,进行数据查询的时候就可能需要关联多张表,这不但代价昂贵。
6. 反范式化
6.1 概念
有的时候不能简单按照规范要求设计数据表,因为有的数据看似冗余,其实对业务来说十分重要。这个时候,我们就要遵循业务优先的原则,首先满足业务需求,再尽量减少冗余。
如果数据库中的数据量比较大,系统的UV和PV访问频次比较高,则完全按照MySQL的三大范式设计数据表,读数据时会产生大量的关联查询,在一定程度上会影响数据库的读性能。如果我们想对查询效率进行优化,反范式优化也是一种优化思路。此时,可以通过在数据表中增加冗余字段来提高数据库的读性能。
6.2 规范与性能平衡
- 为满足某种商业目标,数据库性能比规范化数据库更重要
- 在数据规范化的同时,要综合考虑数据库的性能
- 通过在给定的表中添加额外的字段,以大量减少需要从中搜索信息所需的时间
- 通过在给定的表中插入计算列,以方便查询
6.3 举例
-
需求:现有一张员工信息表和一张部门信息表,想要查询一个员工所在部门的名称。
-
解决方法:我们对这两张表进行连接查询。
-
问题:如果这个查询操作频率非常高,这样的连接查询就会浪费许多时间。
-
反范式解决:我们可以在员工表增加一个冗余字段department_name字段,直接查询员工表即可,不用每次进行连接查询。
6.3 反范式的问题
- 存储空间变大了
- 一个表中字段做了修改,另一个表中冗余的字段也需要做同步修改,否则数据不一致
- 若采用存储过程来支持数据的更新、删除等额外操作,如果更新频繁,会非常消耗系统资源
- 在数据量小的情况下,反范式不能体现性能的优势,可能还会让数据库的设计更加复杂
6.4 反范式的适用场景
当冗余信息有价值或者能大幅度提高查询效率的时候(查询频率 >>> 修改频率),我们才会采取反范式的优化。