MySqL(加餐)
范式
第一范式
- 数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,对象等非原子数据。
- 在关系型数据库的设计中,满足第一范式是对关系模式的基本要求。不满足第一范式的数据库就不能被称为关系数据库。
第一范式实际上只要用普通的数据类型描述每一个元素,就可以满足第一范式。
如下就不满足第一范式 ,因为学校中有多个数据类型。
修改之后就满足第一范式,虽然有很多冗余项。
第二范式
候选键实际上就是标识数据唯一性的。
如图内容就不满足第二范式,
- 这张表中使用学号 + 课程名定义复合主键来唯一标识一个学生某门课程的成绩,这也是这张表的主要作用。
- 学生是通过学号来确定的,学生的姓名、年龄和性别和课程没有关系,即学生的信息只依赖学号,不依赖课程名;学分是通过课程来确定的,课程的学分与学生没有关系,即学分只依赖课程名,不依赖学生
- 对于使用复合主键的表,如果一行数据中的有些列只与复合主键中的一个或其中几个列有关系,那么就说他存在部分函数依赖,也就不满足第二范式
简单来说,学生姓名年龄,性别都只依赖于学号,课程名的学分只依赖于课程名。但是成绩同时依赖于学号和课程名。
解决方法:应该要设计三张表,即学生表,课程表,成绩表。
这时候就可以通过三张表将学生内容组合在一起了,排除了部分函数依赖,不存在复合主键就天生满足第二范式。
可能会出现的问题:
数据冗余
学生的姓名、年龄、性别和课程的学分在每行记录中重复出现,造成了大量的数据冗余。(多个考试有个记录)更新异常
如果要调整 MySQL 的学分,那么就需要更新表中所有关于 MySQL 的记录,一旦执行中断导致某些记录更新成功,某些数据更新失败,就会造成表中同一门课程出现不同学分的情况,出现数据不一致问题。插入异常
目前这样的设计,成绩与每一门课和学生都有对应关系,也就是说只有学生参加选修课程考试取得了成绩才能生成一条记录。当有一门新课还没有学生参加考试取得成绩之前,那么这门新课在数据库中是不存在的,因为成绩为空时记录没有意义。删除异常
把毕业学生的考试数据全都删除,此时课程和学分的信息也会被删除掉,有可能导致一段时间内,数据库里没有某门课程和学分的信息。
第三范式
在满足第二范式的情况下,不存在非关键字段,对任一候选键的依赖传递。
实际上像学院就可以通过学号找到,也就是学院依赖于学号,因为找到了学号也就是找到了学生所属的学院。所以此时就可以对表进行拆分。
把表进行拆分,通过学院Id来进行关联就可以了,第三范式我认为是第二范式的扩充,从一个关系找到另外一个关系就是依赖。
反范式设计
当我们不想要太多次表关联查询,就可以使用反范式进行设计表结构,比如我不想关联表进行查询学院名称,就可以直接在学生表进行字段的增加。减少表连接操作,提升效率。
数据库设计过程
我们一般通过E-R图来表示实体和实体之间的关系。
E-R 图包含了以下三种基本成分:
- 实体:即数据对象,用矩形框表示,比如用户、学生、班级等。
- 属性:实体的特性,用椭圆形或圆角矩形表示,如学生的姓名、年龄等。
- 关系:实体之间的联系,用菱形框表示,并标明关系的类型,并用直线将相关实体与关系连接起来。
一对一
我们可以在drawio上绘制这些关系图,E-R图有一对一,一对多,多对多的关系
一对多
多对多
如果我们生成多张表,并且满足三个范式,就可以画出如下的关系图,根据考试的成绩关联在一起。
数据库设计练习
用户表和账户表一对一
当用户账户表一对一的时候,我们就可以在用户表中多创建一个账户主键id进行维护,这样就能通过该id查找到账户表中的内容。
一对多的关系
如果一个班级对应着多个学生,那么学生表中就要创建一个字段来存储对应的班级id。在多方的表中增加字段。
多对多的关系
如果是学生和课程多对多的话,我们建立关系就要进行增加另外一张表的方式来进行操作,多建立一张成绩表,分别记录学生和课程的关系。
逆向导出EE-R图
如图即为逆向导出EER图,就能看到表之间的关联关系。