数据库范式(学习笔记)
以前在学校做项目时,用到数据库时,就CRUD.以为数据真简单,也就查询语句有点小复杂,多看看查询语句就好了,实在不会上网查查,现在想想还是太年轻了。最近来看数据库,发现好多东西都记不住了。今天在这复习一下,并且写进博客,方便以后查阅复习。
知识点
设计关系数据库时,遵从不同的规范要求
,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。目前关系数据库有六种范式:
第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)`。
Tip
: 范式理论是为了解决下面提到的四种异常。
高级别范式的依赖于低级别的范式,1NF 是最低级别的范式。
一定要看下,有助于下面的理解
-
实体:现实世界中客观存在并可以被区别的事物。比如“一个学生”、“一本书”、“一门课”等等。值得强调的是这里所说的“事物”不仅仅是看得见摸得着的“东西”,它也可以是虚拟的,不如说“老师与学校的关系”。
- 还是不理解?其实就是对应数据库的表,一个实体对应一张表,但是有的时候,有些表不是实体,是实体与实体之间的关系的体现,比如说“老师与学生的关系”。
-
属性:教科书上解释为:“实体所具有的某一特性”,由此可见,属性一开始是个逻辑概念,比如说,“性别”是“人”的一个属性。在关系数据库中,属性又是个物理概念,
属性可以看作是“表的一列”,还有一个名称“字段”
。 -
元组:表中的一行就是一个元组,
对应一张表的一条记录
。 -
分量:元组的某个属性值。在一个关系数据库中,它是一个操作原子,即关系数据库在做任何操作的时候,属性是“不可分的”。否则就不是关系数据库了。
-
码:表中可以唯一确定一个元组的某个属性(或者属性组),如果这样的码有不止一个,那么大家都叫
候选码,我们从候选码中挑一个出来做老大,它就叫主码。 -
全码:如果一个码包含了所有的属性,这个码就是全码。
-
主属性:一个属性只要在任何一个候选码中出现过,这个属性就是主属性。
-
非主属性:与上面相反,没有在任何候选码中出现过,这个属性就是非主属性。
-
外码:一个属性(或属性组),它不是码,但是它别的表的码,它就是外码。
-
候选码: 若关系中的某一属性或属性组的值能唯一的标识一个元组,而其任何真子集都不能再标识,则称该属性组为(超级码)候选码。
关系模式的规范化
如果不进行数据规范化,会产生一些问题:(面试可能会问到)
-
数据冗余:一样的数据一直出现,多余的数据。
-
插入异常:如果由于某些原因主键暂时还没有或者还没全,其他数据也不能插入。
-
删除异常:如果一些记录删了其他的与之无关的记录也会被跟着删掉。
-
更新异常:一个数据进行了修改需要将所有与该数据有关的元组的该数据全改了,容易出现错误。
函数依赖
-
若在一张表中,
在属性(或属性组)X的值确定的情况下,必定能确定属性Y的值
,那么就可以说Y函数依赖于X,写作 X → Y。 -
对于 A->B,如果能找到 A 的真子集 A’,使得 A’-> B,那么 A->B 就是
部分函数依赖
,否则就是完全函数依赖
。 -
对于 A->B,B->C,则 A->C 是一个
传递函数依赖
。
ep:
学生课程关系的函数依赖为 Sno, Cname -> Sname, Sdept, Mname, Grade,键码为 {Sno, Cname}。也就是说,确定学生和课程之后,就能确定其它信息。
Sno | Sname | Sdept | Mname | Cname | Grade |
---|---|---|---|---|---|
1 | 学生-1 | 学院-1 | 院长-1 | 课程-1 | 90 |
2 | 学生-2 | 学院-2 | 院长-2 | 课程-2 | 80 |
2 | 学生-2 | 学院-2 | 院长-2 | 课程-1 | 100 |
3 | 学生-3 | 学院-2 | 院长-2 | 课程-2 | 95 |
- 冗余数据:例如 学生-2 出现了两次。
- 修改异常:修改了一个记录中的信息,但是另一个记录中相同的信息却没有被修改。
- 删除异常:删除一个信息,那么也会丢失其它信息。例如删除了 课程-1 需要删除第一行和第三行,那么 学生-1 的信息就会丢失。
- 插入异常:例如想要插入一个学生的信息,如果这个学生还没选课,那么就无法插入。
先给个图,方便以后自己回想。
###第一范式(1NF——不可再分割 )
定义:数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,记录等非原子数据项。如果实体中的某个属性有多个值时,必须拆分为不同的属性。
通俗点讲,就是列不可再分
,而且在我们用的数据库创建的表,都满足第一范式,这样说还是很懵?。比如说一个表:学生表(姓名,性别,电话(移动电话,家庭电话))
,可以看到这张表里有一个属性电话
有两个值:移动电话,家庭电话,该列就可分的。所以不满足1NF,为什么说数据库的已创建的表满足1NF就是这个原因,你不可能在一个列里面创建两个属性。
注:这里说的数据库指的是**关系型数据**库
###第二范式 (2NF——无部分依赖 )
定义:满足第一范式前提,且每一个非主属性完全函数依赖于码
只有当一个表中,主码由两个或以上的属性组成的时候,才会出现不符合第二范式的情况。
-
满足第一范式。即满足列的原子性,不可再分。
-
表中的每一个非主属性,必须完全依赖于本表码。
-
第三点,要注意了,即没有包含在主键中的列或者说属性必须完全依赖于主键,而不能只依赖于主键的一部分。
比如说一个表如下( 不符合 第二范式):
学号| 课程号 | 成绩 | 课程名 |
-------|----------
(错误示例)
主键:学号、课程号
为啥不满足第二范式呢,这个表有两个非主属性(成绩、课程名)。
- (学号、课程号)—>成绩
- (课程号)—>课程名
可以看出课程名依赖课程号,即出现了部分依赖的情况,所有不满足第二范式。
所以出现上面这个情况,应该让怎么做呢才能满足第二范式呢?,我们应该把这个属性和主关键字的这一部分应该分离出来形成一个新的实体,即一张表,这是新实体与原实体之间是一对多的关系。
学号| 课程号 | 成绩 |
-------|----------
分离出这个新的表
课程号 | 课程名 |
---|
第二范式(2NF)要求实体的属性完全依赖于主关键字。 换句话说,第二范式就是在第一范式的基础上属性完全依赖于主键。
###第三范式(3Nf——无传递依赖)
定义:在满足第二范式的基础上,且每一个非主属性既不部分依赖于码也不传递依赖于码。
-
满足第二范式
-
不能出现,非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
ep:
学号| 系别 | 系主任 |
-------|----------
主键:学号
该示例是不满足第三范式,其中有如下关系:
系主任可以有系别确定,系别也可以由学号确定。即
学号—>系别—>系主任
出现传递依赖,所有不满足第三范式。符合3NF要求的数据库设计,基本上解决了数据冗余过大,插入异常,修改异常,删除异常的问题。
##补充
###BCNF范式(来自知乎解答)
要了解 BCNF 范式,那么先看这样一个问题:
ep:
- 某公司有若干个仓库;
- 每个仓库只能有一名管理员,一名管理员只能在一个仓库中工作;
- 一个仓库中可以存放多种物品,一种物品也可以存放在不同的仓库中。每种物品在每个仓库中都有对应的数量。
那么关系模式 仓库(仓库名,管理员,物品名,数量) 属于哪一级范式?
已知函数依赖集:仓库名 → 管理员,管理员 → 仓库名,(仓库名,物品名)→ 数量
码:(管理员,物品名),(仓库名,物品名)
主属性:仓库名、管理员、物品名
非主属性:数量
不存在非主属性对码的部分函数依赖和传递函数依赖。∴ 此关系模式属于3NF。
仓库名 | 管理员 | 物品名 | 数量
-------|----------
既然此关系模式已经属于了 3NF,那么这个关系模式是否存在问题呢?
我们来看以下几种操作:
-
先新增加一个仓库,但尚未存放任何物品,是否可以为该仓库指派管理员?——不可以,因为物品名也是主属性,根据实体完整性的要求,主属性不能为空。
-
某仓库被清空后,需要删除所有与这个仓库相关的物品存放记录,会带来什么问题?——仓库本身与管理员的信息也被随之删除了。
-
如果某仓库更换了管理员,会带来什么问题?——这个仓库有几条物品存放记录,就要修改多少次管理员信息。
从这里我们可以得出结论,在某些特殊情况下,即使关系模式符合 3NF 的要求,仍然存在着插入异常,修改异常与删除异常的问题,仍然不是 ”好“ 的设计。
造成此问题的原因:存在着主属性对于码的部分函数依赖与传递函数依赖。
(在此例中就是存在主属性【仓库名】对于码【(管理员,物品名)】的部分函数依赖。
解决办法就是要在 3NF 的基础上消除主属性对于码的部分与传递函数依赖。
仓库(仓库名,管理员)
仓库名 | 管理员 |
---|
库存(仓库名,物品名,数量)
仓库名 |物品名|数量
-------|----------
这样,之前的插入异常,修改异常与删除异常的问题就被解决了。
这里通俗点的讲下自己的理解。
BCNF:满足3NF,且满足主属性不依赖主属性
即:BCNF既判断非主属性,又判断主属性。当只判断非主属性时,就成了第三范式。
还可以这么说:若一个关系达到了第三范式,并且它只有一个候选码,或者它的每个候选码都是单属性(非多个属性组合而成的候选码),则该关系自然达到BCNF。
先总结到这里。