摘要:本文学习了关系数据库中涉及范式的相关知识。
环境
Windows 10 企业版 LTSC 21H2
MySQL 5.7.40
1 定义
设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。
但是有些时候一昧的追求范式减少冗余,反而会降低数据读写的效率,这个时候就要反范式,利用空间来换时间。
2 名词
想要正确理解范式的知识,必须先对涉及到的概念名词有一定的了解。
假设有如下两张表:
- 学生表:编号,姓名,身份证号,教师编号
- 教师表:编号,姓名
定义:
- 实体:可以理解为表,一张表可以看做是一种实体。
- 属性:可以理解为表的字段,一个字段可以看做是一个属性。
- 元组:可以理解为表的记录,一条记录可以看做是一个元组。
- 超键:能唯一标识元组的属性集。对于学生表来说,超键包括(编号),(编号,姓名),(编号,姓名,身份证号)等等。
- 候选键:能唯一标识元组的最小属性集,是超键的精简。对于学生表来说,候选键就是(编号)和(身份证号)。
- 主键:从候选键选择一个属性集作为主键。对于学生表来说,主键一般是(编号)。
- 外键:在其他实体中作为主键的属性集。对于学生表来说,外键是(教师编号)。对于教师表来说,主键是(编号)。
- 主属性:所有候选键中的属性。
- 非主属性:不在候选键中的属性。
3 说明
目前关系数据库有六种范式:
- 第一范式(1NF)
- 第二范式(2NF)
- 第三范式(3NF)
- 巴斯-科德范式(BCNF,又称为修正的第三范式)
- 第四范式(4NF)
- 第五范式(5NF,又称完美范式)
满足最低要求的范式是第一范式(1NF),在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。
一般说来,数据库只需满足第三范式(3NF)就行了。
3.1 第一范式(1NF)
要求每个属性都是原子数据项,即每个属性只包含一个值,并且不能有重复的属性。
第一范式确保表中的每个属性都是不可分割的基本数据项。
违背第一范式的数据:
编号 | 姓名 | 课程 |
---|---|---|
201010 | 张三 | 语文;数学 |
201011 | 李四 | 语文 |
在课程中存在多个值的情况,违背了第一范式。
修改后的数据:
编号 | 姓名 | 课程 |
---|---|---|
201010 | 张三 | 语文 |
201010 | 张三 | 数学 |
201011 | 李四 | 语文 |
3.2 第二范式(2NF)
要求在满足第一范式的基础上,非主属性完全依赖候选键,不能部分依赖候选键。
第二范式确保在候选键为属性组的情况下,表中没有部分依赖问题。
违背第二范式的数据:
编号 | 姓名 | 课程 | 成绩 |
---|---|---|---|
201010 | 张三 | 语文 | 97 |
201010 | 张三 | 数学 | 99 |
201011 | 李四 | 语文 | 94 |
将编号和课程作为候选键,共同决定成绩,但姓名只依赖编号,存在部分依赖的情况,违背了第二范式。
修改后的数据:
编号 | 课程 | 成绩 |
---|---|---|
201010 | 语文 | 97 |
201010 | 数学 | 99 |
201011 | 语文 | 94 |
将编号和姓名单独拆分出来:
编号 | 姓名 |
---|---|
201010 | 张三 |
201011 | 李四 |
3.3 第三范式(3NF)
要求在满足第二范式的基础上,非主属性只能依赖主属性,不能依赖其他非主属性。
第三范式确保表中没有传递依赖问题。
违背第三范式的数据:
编号 | 姓名 | 目标 | 省市 |
---|---|---|---|
201010 | 张三 | 山东大学 | 山东省 |
201011 | 李四 | 北京大学 | 北京市 |
将编号作为主键,编号决定报考的目标,报考的目标决定所在的省市,存在传递依赖的情况,违背了第三范式。
修改后的数据:
编号 | 姓名 | 目标 |
---|---|---|
201010 | 张三 | 山东大学 |
201011 | 李四 | 北京大学 |
将目标和省市单独拆分出来:
目标 | 省市 |
---|---|
山东大学 | 山东省 |
北京大学 | 北京市 |
3.4 巴斯-科德范式(BCNF)
要求在满足第三范式的基础上,主属性完全依赖候选键,不能部分依赖候选键。
巴斯-科德范式确保在候选键为属性组的情况下,表中没有部分依赖和传递依赖问题。
违背巴斯-科德范式的数据:
编号 | 课程 | 教师 | 成绩 |
---|---|---|---|
201010 | 语文 | 语文老师 | 93 |
201010 | 数学 | 数学老师 | 96 |
201011 | 语文 | 语文老师 | 91 |
将编号和课程作为主键,同时编号和教师作为候选键,都能决定成绩,但是课程也能决定教师,存在主属性部分依赖候选键的情况,违背了巴斯-科德范式。
修改后的数据:
编号 | 课程 | 成绩 |
---|---|---|
201010 | 语文 | 93 |
201010 | 数学 | 96 |
201011 | 语文 | 91 |
将课程和教师单独拆分出来:
课程 | 教师 |
---|---|
语文 | 语文老师 |
数学 | 数学老师 |
3.5 第四范式(4NF)
要求在满足巴斯-科德范式的基础上,当某个属性的值确定时,只能有一条记录与之对应。
第四范式确保表中没有多值依赖问题。
违背第四范式的数据:
编号 | 课程 | 爱好 |
---|---|---|
201010 | 语文 | 跑步 |
201010 | 数学 | 游泳 |
201011 | 语文 | 游泳 |
将编号作为主键,同时对应多个课程和多个爱好,并且课程和爱好之间没有关联,存在多值依赖的情况,违背了第四范式。
修改后的数据:
编号 | 课程 |
---|---|
201010 | 语文 |
201010 | 数学 |
201011 | 语文 |
将编号和爱好单独拆分出来:
编号 | 爱好 |
---|---|
201010 | 跑步 |
201010 | 游泳 |
201011 | 游泳 |
3.6 第五范式(5NF)
又称为完美范式,要求在满足第四范式的基础上,不存在任何通过连接操作生成的冗余数据,即不存在多对多关系。
第五范式确保表中没有连接依赖问题。
违背第五范式的数据:
编号 | 课程 | 考试 |
---|---|---|
201010 | 语文 | 期中 |
201010 | 数学 | 期末 |
201011 | 语文 | 期末 |
将编号作为主键,同时对应多个课程和多种考试,并且课程和考试之间存在多对多的关系,存在连接依赖的情况,违背了第五范式。
修改后的数据:
编号 | 课程 |
---|---|
201010 | 语文 |
201010 | 数学 |
201011 | 语文 |
将编号和考试单独拆分出来:
编号 | 考试 |
---|---|
201010 | 期中 |
201010 | 期末 |
201011 | 期末 |
4 反范式化
在某些业务场景下,为了更方便快速的查询数据,往往会打破范式的规范。
反范式化最常见的场景是字段冗余,通过冗余字段可以避免多表联查,大幅提高查询效率。
冗余字段的特点:
- 通常很少修改。
- 经常需要查询。
5 设计原则
创建数据库的建议:
- 库的名称必须控制在32个字符以内,只能使用英文字母、数字和下划线,建议以英文字母开头。
- 库名中英文一律小写,不同单词采用下划线分割。须见名知意。
- 创建数据库时必须指定字符集,并且字符集只能是utf8或者utf8mb4。
- 对于程序连接数据库账号,遵循权限最小原则。使用数据库账号只能在一个DB下使用,不准跨库。
- 临时库以
tmp_
为前缀,并以日期为后缀。备份库以bak_
为前缀,并以日期为后缀。
创建表的建议:
- 表和列的名称必须控制在32个字符以内,表名只能使用英文字母、数字和下划线,建议以英文字母开头。
- 表名、列名一律小写,不同单词采用下划线分割。须见名知意。
- 表名要求有模块名强相关,同一模块的表名尽量使用统一前缀。
- 创建表时必须指定字符集,并且字符集只能是utf8或者utf8mb4。
- 创建表时必须指定表存储引擎类型。如无特殊需求,一律为InnoDB。
- 创建表时必须说明表的comment内容,说明表的作用。
- 字段命名应尽可能使用表达实际含义的英文单词或缩写。
- 字段为布尔值类型时,命名建议为
is_描述
格式。 - 字段禁止存储图片和文件等大型二进制数据。建议将文件储存在服务器上,数据库只存储文件地址信息。
- 表中必须有主键,强制要求主键为id,并设置为int或bigint类型,并且auto_increment自增。
- 表中必须有行数据的创建时间字段和最后更新时间字段,便于查问题,特别是核心业务相关的表。
- 表中字段尽量都是NOT NULL属性,业务可以根据需要定义DEFAULT值。因为使用NULL值会占用额外存储空间,会导致数据迁移出错和聚合函数计算结果偏差等问题。
- 表中存储相同数据的列名和列类型必须一致。相同的字段一般作为关联列,如果查询时关联列类型不一致会自动进行数据类型隐式转换,会造成列上的索引失效,导致查询效率降低。
- 临时表用于保留临时结果集,名称以
tmp_
开头。备份表用于备份或抓取源表快照,名称以bak_
开头。临时表和备份表定期清理。
创建索引的建议:
- 主键的名称以
pk_
开头,唯一键以uni_
或uk_
开头,普通索引以idx_
开头,一律使用小写格式,以字段的名称或缩写作为后缀。 - 单个表上的索引个数不能超过6个。
- 多考虑建立联合索引,并把区分度最高的字段放在最前面。
- 表里不能存在冗余索引。
条