关系型数据库设计范式总结
Posted YuLong~W
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关系型数据库设计范式总结相关的知识,希望对你有一定的参考价值。
关系型数据库设计范式
范式:Normal Format,符合某一种级别的关系模式的集合,表示一个关系内部各属性之间的联系的合理化程度
-
范式是离散数学里的概念,是一种数学理论
-
范式目标是在满足组织和存储的前提下使数据结构冗余最小化 ,减少数据冗余
-
范式级别越高,即满足的范式越多,表的级别就越标准,越符合高标准表设计
-
目前数据库应用到的范式有以下几层:
- 第一范式:1NF
- 第二范式:2NF
- 第三范式:3NF
- 逆规范化
示例
1、一张员工表
工号 | 姓名 | 部门 | 入职时间 |
---|---|---|---|
0001 | 杨戬 | 武装部 | 0001-01-01 |
0002 | 李白 | 书院部 | 1500-12-12 |
2、每个员工都是与部门挂钩的,但是部门不可能很多,所以上述表中会有很多数据重复,此时应该将部门单独维护出来,减少数据冗余
部门编号 | 部门名称 |
---|---|
1 | 武装部 |
2 | 书院部 |
工号 | 姓名 | 部门编号 | 入职时间 |
---|---|---|---|
0001 | 杨戬 | 1 | 0001-01-01 |
0002 | 李白 | 2 | 1500-12-12 |
N个1和N个武装部占用的磁盘空间肯定是不一样的
第一范式1NF
第一范式:1NF,数据字段设计时必须满足原子性
- 1NF是满足数据表设计的最基础规范
- 原子性:字段数据颗粒度最小,保证数据取出来使用的时候不用再拆分,就可以直接应用
- 如果数据使用的时候需要进行拆分那么就违背1NF
步骤:
- 判断设计的字段是否在使用的时候还需要再拆分
- 将数据拆分到最小单位(使用),然后设计成字段
- 满足1NF
示例
1、设计一张学生选修课成绩表
学生 | 性别 | 课程 | 教室 | 成绩 | 学习时间 |
---|---|---|---|---|---|
张三 | 男 | php | 101 | 100 | 2月1日,2月28日 |
李四 | 女 | Java | 102 | 90 | 3月1日,3月31日 |
张三 | 男 | Java | 102 | 95 | 3月1日,3月31日 |
当前表的学习时间在使用的时候肯定是基于开始时间和结束时间的,而这种设计就会存在使用时的数据拆分,不满足原子性也就是1NF
2、满足1NF的设计:字段颗粒度应用层最小(不需要拆分)
学生 | 性别 | 课程 | 教室 | 成绩 | 开始时间 | 结束时间 |
---|---|---|---|---|---|---|
张三 | 男 | PHP | 101 | 100 | 2月1日 | 2月28日 |
李四 | 女 | Java | 102 | 90 | 3月1日 | 3月31日 |
张三 | 男 | Java | 102 | 95 | 3月1日 | 3月31日 |
第二范式2NF
第二范式:2NF,字段设计不能存在部分依赖
- 部分依赖:首先表存在复合主键,其次有的字段不是依赖整个主键,而只是依赖主键中的一部分
- 部分依赖解决:让所有非主属性都依赖一个候选关键字
- 最简单方式:取消复合主键(一般选用逻辑主键替代,但是本质依然是复合主键做主),所有非主属性都依赖主属性(逻辑主键)
- 正确方式:将部分依赖关系独立成表,不存在部分依赖关系的独立成表
- 2NF是在满足1NF的前提之上的,2NF可以实现很大程度的数据冗余减少
步骤:
- 判断表中是否存在复合主键
- 判断其他字段是否存在依赖主键中的一部分
- 如果存在部分依赖,将部分依赖的关系独立拆分成表
- 满足2NF
示例
1、学生成绩表中学生和课程应该是决定性关系,因此属于主属性(主键)
学生(P) | 性别 | 课程(P) | 教室 | 成绩 | 开始时间 | 结束时间 |
---|---|---|---|---|---|---|
张三 | 男 | PHP | 101 | 100 | 2月1日 | 2月28日 |
李四 | 女 | Java | 102 | 90 | 3月1日 | 3月31日 |
张三 | 男 | Java | 102 | 95 | 3月1日 | 3月31日 |
- 成绩是由学生和课程决定的,是完全依赖主属性
- 性别只依赖学生(部分依赖)
- 教室、开始时间和结束时间依赖课程(部分依赖)
2、解决方案:将学生信息维护到一张表,课程信息维护到一张表,成绩表取两个表的主属性即可
学生表
Stu_id(P) | 姓名 | 性别 |
---|---|---|
1 | 张三 | 男 |
2 | 李四 | 女 |
- Stu_id是姓名的代指属性(逻辑主键,本质主键是姓名)
- 性别只依赖主属性
课程表
Class_id(P) | 课程 | 教室 | 开始时间 | 结束时间 |
---|---|---|---|---|
1 | PHP | 101 | 2月1日 | 2月28日 |
2 | Java | 102 | 3月1日 | 3月31日 |
- Class_id是课程的代指属性(逻辑主键)
- 教室、开始时间和结束时间都依赖课程(主属性)
成绩表
Stu_id(P) | Class_id(P) | 成绩 |
---|---|---|
1 | 1 | 100 |
2 | 2 | 90 |
1 | 2 | 95 |
- Stu_id和Class_id共同组成主属性(复合主键)
- 成绩依赖Stu_id和Class_id本身,不存在部分依赖
第三范式3NF
第三范式:3NF,字段设计不能存在传递依赖
- 传递依赖:字段某个非主属性不直接依赖主属性,而是通过依赖某个其他非主属性而传递到主属性之上
- 传递依赖解决:让依赖非主属性的字段与依赖字段独立成表
步骤:
- 确定表中的所有字段都是依赖主属性的
- 如果存在不直接依赖主属性,而是通过依赖其他属性产生依赖的,形成独立的表
- 满足3NF
示例
1、学生表:包括所在系信息
学号(P) | 姓名 | 专业编号 | 专业名字 |
---|---|---|---|
1 | 张三 | 0001001 | 软件工程 |
2 | 李四 | 0001002 | 土木工程 |
- 姓名和专业编号都依赖于学号(为学号提供信息支持)
- 专业名字依赖专业编号(为编号提供信息支持)
- 专业名字间接依赖学号:传递依赖
- 随着学生增加,专业名字会出现大量数据冗余
2、解决方案:将存储传递依赖部分的字段(非主属性)独立成表,然后在需要使用相关信息的时候,引入即可
专业表
专业编号(P) | 专业名字 |
---|---|
0001001 | 软件工程 |
0001002 | 土木工程 |
- 即使有更多的信息为专业提供支持也不存在传递关系
学生表
学号(P) | 姓名 | 专业编号 |
---|---|---|
1 | 张三 | 0001001 |
2 | 李四 | 0001002 |
- 姓名和专业编号都依赖学号(为学号提供信息支持)
- 没有其他字段是通过非主属性(专业编号)来依赖主属性的:没有传递依赖
- 学生再多,专业名字信息只需要维护一次,减少数据冗余
逆规范化
逆规范化:为了提升数据查询的效率而刻意违背范式的规则
- 逆规范化的目标是为了提升数据访问效率
- 所谓逆规范化就是减少表之间的关联查询(效率降低),刻意增加数据冗余
- 逆规范化只有在数据量大,查询效率低下的时候为了提升查询效率而牺牲磁盘空间的一种做法
- 逆规范化后数据表的设计必然是不完全符合范式要求的(2NF/3NF)
步骤:
- 表中部分数据来源于其他表(通常只需要其他表的某个简单数据)
- 当前表会被高频次查询
- 数据表数据量很大
- 考虑使用逆规范化
示例
1、学生成绩表需要经常查询,而且数据量很大,但是:
- 成绩表中只有学号,显示的时候需要学生姓名(去学生表中连表查询)
- 成表表中只有课程号,显示的时候需要显示课程名(去课程表中连表查询)
- 逆规范化:将学生姓名和课程名在表中冗余维护(不满足2NF)
学号(P) | 学生姓名 | 课程号(P) | 课程名字 | 成绩 |
---|---|---|---|---|
1 | 张三 | 1 | PHP | 100 |
1 | 张三 | 2 | Java | 90 |
- 学生姓名部分依赖学号(主属性):不满足2NF
- 学生姓名和课程名字会有大量数据冗余存在(不满足2NF导致)
总结
1、范式是关系型数据库设计借鉴用来减少数据冗余的
- 1NF:数据字段的原子性,增强数据的可用性
- 2NF:取消字段的部分依赖,建立数据的关联性,减少数据冗余
- 3NF:取消字段的传递依赖,将相关实体独立划分,减少数据冗余
- 逆规范化:为了提升数据访问效率,刻意增加数据冗余(磁盘空间利用率与访问效率的矛盾)
2、在进行数据表设计的时候,需要严格遵循范式规范
- 基于规范设计数据表
- 在设计表中深入认知范式规范
- 熟练的基于业务设计数据表
以上是关于关系型数据库设计范式总结的主要内容,如果未能解决你的问题,请参考以下文章