数据库中的范式
数据库中的范式
导语
在关系型数据库中,对关系模式的基本要求是满足第一范式。这样的关系模式就是合法的、允许的。但是,人们发现这些关系模式存在插入,删除异常,修改复杂,数据冗余等毛病,于是就进行了规范化处理,引出了四种范式。
候选键:唯一标识记录的属性集合,一个表中可以有多个候选键。比如(A,B,C)可以决定一条记录,(B,C,D)也可以决定一条记录,这两个都是可以称为候选键
主键:在实际生产中一般都固定选择候选键中的某一个来使用,我们称为主键。主键是候选键的子集。
主属性:位于候选键中的属性
非主属性:不在候选键中的属性
第一范式
若关系R(U)中每个分量都不可分,则称R(U)属于第一范式,记为R(U)∈1NF。
- 不符合1NF(出现复合属性和多值属性)
选课列中出现多值属性
学号 | 姓名 | 选课 |
---|---|---|
10001 | 张三 | 数学,语文,英语 |
10002 | 李四 | 语文,英语 |
- 符合1NF
学号 | 姓名 | 选课 |
---|---|---|
10001 | 张三 | 数学 |
10001 | 张三 | 语文 |
10001 | 张三 | 英语 |
10002 | 李四 | 语文 |
10002 | 李四 | 英语 |
第二范式
若R(U)∈1NF且U中的每一个非主属性完全函数依赖于候选键,则称R(U)属于第二范式,记为:R(U)∈2NF
第二范式消除了关系中非主属性对候选键的部分依赖
学号 | 课程 | 成绩 | 学分 |
---|---|---|---|
10001 | 数学 | 100 | 6 |
10001 | 语文 | 90 | 2 |
10001 | 英语 | 85 | 3 |
10002 | 数学 | 90 | 6 |
10003 | 数学 | 99 | 6 |
10004 | 语文 | 89 | 2 |
第二范式解决的问题
选课关系SCI(学号,课程,成绩,学分),候选键为(学号,课程),该表中存在部分依赖:学分->课程
存在的问题
- 数据冗余:假设同一门课由40个学生选修,学分就重复40次
- 更新异常:若学校调整了某课程的学分,表中学分的属性值都需要更新(比如更新40多次),如果更新出现失误,则会出现同一门课程学分不一致的状况
- 插入异常:比如添加新的课程,但是没有人选修,而关键字为(学号,课程),导致课程无法添加
我们对SCI表重新设计,拆分成两个表,让其满足2NF
选课表:
学号 | 课程 | 成绩 |
---|---|---|
10001 | 数学 | 100 |
10001 | 语文 | 90 |
10001 | 英语 | 85 |
10002 | 数学 | 90 |
10003 | 数学 | 99 |
10004 | 语文 | 89 |
课程表:
课程 | 课程学分 |
---|---|
数学 | 6 |
语文 | 3 |
英语 | 2 |
选课表:成绩->(学号,课程)
课程表:学分->课程
第三范式
第三范式要求非主属性直接依赖于候选键,消除非主属性对候选键的传递依赖
学号 | 姓名 | 性别 | 班级 | 班主任 |
---|---|---|---|---|
10001 | 张三 | 男 | 一班 | 小王 |
10002 | 李四 | 男 | 一班 | 小王 |
10003 | 王五 | 男 | 二班 | 小李 |
10004 | 张小三 | 男 | 二班 | 小李 |
首先这张学生表在理解上是没有问题的,通过学号可以找到这个学生、性别、班级以及他的班主任。所以学号作为候选键用来标识一条记录很合理,不存在对候选键的部分依赖,所以是满足第二范式的。但学号和班主任是没有直接关系的,班主任->班级->学号,这就是所谓的传递依赖。
传递依赖的表中存在以下问题:
- 数据冗余:一个班有多个学生,但是只有一个班主任,这会导致班主任出现多次
- 插入异常:学校新开了一班,但是还没有招生,由于没有学号(候选键)导致班级无法插入
- 删除异常:如果该班的学生都毕业了(学号已被删除)还没来得及招收新的学生,会导致这个班都不存在。当然,班是由学生组成的,学生都没有要班级干啥
我们对表重新设计,让其满足3NF
学生表:
学号 | 姓名 | 性别 | 班级 |
---|---|---|---|
10001 | 张三 | 男 | 一班 |
10002 | 李四 | 男 | 一班 |
10003 | 王五 | 男 | 二班 |
10004 | 张小三 | 男 | 二班 |
班级表:
班级 | 班主任 |
---|---|
一班 | 小王 |
二班 | 小李 |
注意
并不是数据库范式越高越好,因为范式越高表的数量越多,查询时连表查询开销越大。因此在实际数据库开发中,往往会在范式和数据冗余之间进行平衡