MySQL学习笔记(16)--关系型数据库设计范式

·概念

范式: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个武装部占用的磁盘空间肯定是不一样的

小结

1、范式是一种数学理论,在关系型数据库上用来减少数据冗余

2、满足的范式越多,越符合高标准表设计

3、范式一共有6层,但是数据库的设计通常只要求满足3层即可

·第一范式1NF

1NF,数据字段设计时必须满足原子性

  • 1NF要求字段数据是不需要拆分就可以直接应用
  • 如果数据使用的时候需要进行拆分那么就违背1NF

步骤

1、设计的字段是否在使用的时候还需要再拆分?

2、将数据拆分到最小单位(使用),然后设计成字段

3、满足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日

小结

1、1NF就是要字段数据颗粒度最小,保证数据取出来使用的时候不用再拆分

2、1NF是满足数据表设计的最基础规范

·第二范式2NF

2NF,字段设计不能存在部分依赖

  • 部分依赖:首先表存在复合主键,其次有的字段不是依赖整个主键,而只是依赖主键中的一部分
  • 部分依赖解决:让所有非主属性都依赖一个候选关键字
    • 最简单方式:取消复合主键(一般选用逻辑主键替代,但是本质依然是复合主键做主),所有非主属性都依赖主属性(逻辑主键)
    • 正确方式:将部分依赖关系独立成表

步骤

1、表中是否存在复合主键?

2、其他字段是否存在依赖主键中的一部分?

3、如果存在部分依赖,将部分依赖的关系独立拆分成表

4、满足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本身,不存在部分依赖

小结

1、2NF是在满足1NF的前提之上的

2、2NF的目标是取消表中存在的部分依赖

  • 主属性(主键)为复合主键才有可能存在
  • 解决方案就是让部分依赖存在的关系独立成表(学生表和课程表),不存在部分依赖关系的独立成表(学生成绩表)

3、2NF可以实现很大程度的数据冗余减少

·第三范式3NF

3NF,字段设计不能存在传递依赖

  • 传递依赖:字段某个非主属性不直接依赖主属性,而是通过依赖某个其他非主属性而传递到主属性之上
  • 传递依赖解决:让依赖非主属性的字段与依赖字段独立成表

步骤

1、确定表中的所有字段都是依赖主属性的

2、如果存在不直接依赖主属性,而是通过依赖其他属性产生依赖的,形成独立的表

3、满足3NF

示例

1、学生表:包括所在系信息

学号(P) 姓名 专业编号 专业名字
1 张三 0001001 软件工程
2 李四 0001002 土木工程
  • 姓名和专业编号都依赖于学号(为学号提供信息支持)
  • 专业名字依赖专业编号(为编号提供信息支持)
  • 专业名字间接依赖学号:传递依赖
  • 随着学生增加,专业名字会出现大量数据冗余

2、解决方案:将存储传递依赖部分的字段(非主属性)独立成表,然后在需要使用相关信息的时候,引入即可

专业表

专业编号(P) 专业名字
0001001 软件工程
0001002 土木工程
  • 即使有更多的信息为专业提供支持也不存在传递关系

学生表

学号(P) 姓名 专业编号
1 张三 0001001
2 李四 0001002
  • 姓名和专业编号都依赖学号(为学号提供信息支持)
  • 没有其他字段是通过非主属性(专业编号)来依赖主属性的:没有传递依赖
  • 学生再多,专业名字信息只需要维护一次,减少数据冗余

小结

1、3NF目的是为了解决非主属性对主属性的传递依赖

2、让有关联关系的表独立成表就可以消除传递依赖,满足3NF

·逆规范化

为了提升数据查询的效率刻意违背范式的规则

  • 逆规范化的目标是为了提升数据访问效率
  • 所谓逆规范化就是减少表之间的关联查询(效率降低),刻意增加数据冗余

步骤

1、表中部分数据来源于其他表(通常只需要其他表的某个简单数据)

2、当前表会被高频次查询

3、数据表数据量很大

4、考虑使用逆规范化

示例

1、学生成绩表需要经常查询,而且数据量很大,但是:

  • 成绩表中只有学号,显示的时候需要学生姓名(去学生表中连表查询)
  • 成表表中只有课程号,显示的时候需要显示课程名(去课程表中连表查询)
  • 逆规范化:将学生姓名和课程名在表中冗余维护(不满足2NF)
学号(P) 学生姓名 课程号(P) 课程名字 成绩
1 张三 1 PHP 100
1 张三 2 Java 90
  • 学生姓名部分依赖学号(主属性):不满足2NF
  • 学生姓名和课程名字会有大量数据冗余存在(不满足2NF导致)

小结

1、逆规范化只有在数据量大,查询效率低下的时候为了提升查询效率而牺牲磁盘空间的一种做法

2、逆规范化后数据表的设计必然是不完全符合范式要求的(2NF/3NF)

·总结

1、范式是关系型数据库设计借鉴用来减少数据冗余

  • 1NF:数据字段的原子性,增强数据的可用性
  • 2NF:取消字段的部分依赖,建立数据的关联性,减少数据冗余
  • 3NF:取消字段的传递依赖,将相关实体独立划分,减少数据冗余
  • 逆规范化:为了提升数据访问效率,刻意增加数据冗余(磁盘空间利用率与访问效率的矛盾)

2、在进行数据表设计的时候,需要严格遵循范式规范

  • 基于规范设计数据表
  • 在设计表中深入认知范式规范
  • 熟练的基于业务设计数据表

你可能感兴趣的:(MySQL)