简述数据库设计--范式、ER图
1.范式
数据库的范式是⼀组规则。在设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数 据库,这些不同的规范要求被称为不同的范式。 、
关系数据库有六种范式:第⼀范式(1NF)、第⼆范式(2NF)、第三范式(3NF)、巴斯-科德 范式(BCNF)、第四范式(4NF)和第五范式(5NF,⼜称完美范式),越⾼的范式数据库冗余越 ⼩。
范式越⾼虽然对数据关系有更好的约束性,但也可能导致数据库IO更繁忙,因此在实际应⽤中,数据库设计通常只需满足第三范式即可。
1.1 第一范式
定义:
- 数据库表的每⼀列都是不可分割的原子数据项,⽽不能是集合,数组,对象等⾮原⼦数据。
- 在关系型数据库的设计中,满足第⼀范式是对关系模式的基本要求。不满足第一范式的数据库就不能被称为关系数据库。
下面的表不满足第一范式:学校是⼀个对象,可以继续进⾏拆分,所以不满⾜第⼀范式

把“学校”列分成分成不可再分的原子后数据项后,就满足了第一范式:

1.2 第二范式
定义:在满足第⼀范式的基础上,不存在非关键字段对任意候选键的部分函数依赖。
- 关键字段:一个主键可以由多个列组成,这些组成主键的列就是关键字段。
- 部分函数依赖:假设一个复合主键α由 A列和B列 组成,现在存在普通列C列 且 C列的值能够只由A列确定 (由某列确定另一列就是函数依赖) ,那么就可以说 存在非关键字段C对于候选键α的部分函数依赖。
- 讨论是否满足第二范式的情况通常发生在表中定义了复合主键的情况下。
举例 --- 建表需求:学⽣可以选修课程,课程有对应的学分,学⽣考试后每⻔课程会产⽣相应的成绩
反例实现:如果⽤⼀张表记录所有信息,我们发现如果要指定唯一的成绩,那么主键必须由学号+课程名组成。如下:
学生课程成绩表:
| 学号 | 学生姓名 | 年龄 | 性别 | 课程名 | 学分 | 成绩 | |--------|----------|------|------|--------|------|------| | 10001 | 张三 | 18 | 男 | MySQL | 50 | 98 | | 10002 | 李四 | 19 | 女 | MySQL | 50 | 10 | | 10003 | 王五 | 18 | 男 | MySQL | 50 | 88 | | 10001 | 张三 | 18 | 男 | Java | 60 | 10 | | 10002 | 李四 | 19 | 女 | Java | 60 | 98 | | 10003 | 王五 | 18 | 男 | C++ | 60 | 98 |
我们发现,学生姓名、年龄、性别 都只依赖于学号关键列,课程名只依赖于课程名关键列,这些都是部分函数依赖。(只有成绩是学号+课程名的完全函数依赖)
显然这样的建表方式不符合第二范式。
正例实现:针对需求应该设计三张表,即:学⽣表、课程表和成绩表。
学生表:学生id为主键。(对单主键的完全函数依赖)
| 学生Id | 学号 | 学生姓名 | 年龄 | 性别 |
|-------|--------|----------|------|------|
| 1 | 10001 | 张三 | 18 | 男 |
| 2 | 10002 | 李四 | 19 | 女 |
| 3 | 10003 | 王五 | 18 | 男 |课程表:学生id为主键。(对单主键的完全函数依赖)
| 课程Id | 课程名 | 学分 | |--------|--------|------| | 1 | MySQL | 50 | | 2 | Java | 60 | | 3 | C++ | 60 |
成绩表:复合主键为 学生id + 课程id,该表可以指定唯一的学分(对复合主键的完全函数依赖)。
| 学生Id | 课程Id | 成绩 | |--------|--------|------| | 1 | 1 | 98 | | 2 | 1 | 10 | | 3 | 1 | 88 | | 1 | 2 | 10 | | 2 | 2 | 98 | | 3 | 3 | 98 |
不满足第二范式时可能出现的问题:
- 数据冗余: 例如课程的总学分在每⾏记录中重复出现(课程总学分没必要出现这多次,也难以找到自己想要查看的总学分),造成了⼤量的数据冗余。
- 更新异常: 如果要调整MySQL的学分,那么就需要更新表中所有关于MySQL的记录,⼀旦系统异常中断导致某些 记录更新成功,某些数据更新失败,就会造成表中同⼀门课程出现不同学分的情况,出现数据不⼀致 问题。
- 插入异常: ⽬前这样的设计,成绩与每⼀⻔课和学⽣都有对应关系,也就是说只有学⽣参加选修课程考试取 得了成绩才能⽣成⼀条记录。当有⼀⻔新课还没有学⽣参加考试取得成绩之前,那么这⻔新课在数据 库中是不存在的(新课无法插入),因为成绩为空时记录没有意义。
- 删除异常: 把毕业学⽣的考试数据全都删除,此时课程和学分的信息也会被删除掉,有可能导致⼀段时间内,数据库⾥没有某⻔课程和学分的信息。(把学生删除的同时把课程也删掉了,实际上课程理应依旧存在)
1.3 第三范式
定义:在满足第二范式的基础上,不存在非关键字段对任⼀候选键的传递依赖。
违反第三范式的示例:
学生表:
| 学号 | 姓名 | 学生所在系 | 系主任 | 系地址 |
|--------|------|-----------|-----------|-----------|
| 10001 | 张三 | 计算机 | 李教授 | 科技楼A座 |
| 10002 | 李四 | 计算机 | 李教授 | 科技楼A座 |
| 10003 | 王五 | 数学 | 张教授 | 理科楼B座 |- 主键:学号
- 每个学生的系主任确实是能够只由学号确定,但是存在传递依赖(一个系只有一个系主任):
学号 → 所在系 → 系主任 - 系主任和系地址不直接依赖于学号,而是通过 所在系 间接依赖
符合第三范式的解决方案:
学生表:
| 学号 | 姓名 | 所在系ID |
|--------|------|-----------|
| 10001 | 张三 | 1 |
| 10002 | 李四 | 1 |
| 10003 | 王五 | 2 |院系表:
| 系ID | 系名称 | 系主任 | 系地址 |
|------|--------|-----------|-----------|
| 1 | 计算机 | 李教授 | 科技楼A座 |
| 2 | 数学 | 张教授 | 理科楼B座 |2.设计过程
- 从现实业务中抽象得到概念类
- 概念类是从现实世界中抽象出来的,在需求分析阶段就需要确定下来
- 类对应了数据库设计中的实体,实体对应了数据库中的表
- 类中的属性对应实体中的属性,实体的属性对应了表中的列
- 确定实体与实体之间的关系,并画出E-R画,⽅便项⽬参与⼈员理解与沟通
- 根据E-R图完成SQL语句的编号并创建数据库
3.实体—关系设计图
实体-关系图(Entity-RelationshipDiagram)简称E-R图,也称作实体联系模型、实体关系模型,是 ⼀种⽤于描述数据模型的概念图,主要⽤于数据库设计阶段。
E-R图的3种基本组成:
- 实体:即数据对象,⽤矩形表示,⽐如用户、学⽣、班级等。
- 属性:实体的特性,⽤椭圆形或圆角矩形表示,如学⽣的姓名、年龄等。
- 关系:实体之间的联系,⽤菱形框表示,并标明关系的类型,并⽤直线将相关实体与关系连接起来。
其中,关系又可以分为3种:1对1关系、1对多关系、多对多关系。
一对一关系(1:1)
- ⼀个用户实体包含的属性有:用户昵称,真实姓名,手机号,邮箱地址,性别,学校
- ⼀个账户实体包含的属性有:登录用户名,密码
- 用户实体与账户实体是⼀对⼀的关系,⽤E-R图表示如下:

根据ER图创建的表:(两种实现)
用户表:user(id, name, age, phone_num, mail)
账户表:account(id, username, password, user_id)
- 账号表user_id作为外键与用户表的id进行关联
或
用户表:user(id, name, age, phone_num, mail, account_id)
账户表:account(id, username, password)
- 用户表account_id作为外键与账号表的id进行关联
一对多关系(1:N)
- ⼀个学⽣实体包含的属性有:真实姓名,学号,年龄,性别,⼊学时间
- ⼀个班级实体包含的属性有:班级名,学⽣⼈数
- ⼀个班级中有多个学⽣,所以班级实体与学⽣实体是⼀对多的关系,反过来说学⽣实体与班级实体 是多对⼀着么,⽤E-R图表示如下:

根据ER图创建的表:
学生表:student(id, name, sno, age, gender, enroll_time, class_id)班级表:class(id, name, amount)
- 学生表class_id作为外键与班级表的id进行关联。
- 一对多关系中,必须是“一”方作为主表,“多”方作为从表。(满足第一范式)
多对多关系(M:N)
- ⼀个学⽣实体包含的属性有:真实姓名,学号,年龄,性别,⼊学时间
- ⼀个课程实体包含的属性有:课程名
- ⼀个学⽣可以选修改多⻔课程,⼀⻔课程也可以被多名学⽣选修改,所以学⽣与课程之间是多对多 关系,⽤E-R图表示如下:

根据ER图创建的表:
学生表:user(id, name, sno, age, gender, enroll_time)
课程表:course(id, name, credit)
成绩(关系)表:student_course(id, student_id, course_id, score)
- 成绩表的student_id作为外键与学生表的id进行关联,成绩表的course_id作为外键与课程表的id进行关联
- 在多对多关系中,除了为两个实体创建表,还要单独创建一个关系表。(满足第二范式)
