RaymondHuang
RaymondHuang
发布于 2023-12-14 / 61 阅读
0
0

Chapter 5 —— 数据库的设计与基本范式

数据库的设计流程

· 我们的数据库设计出来是为了解决实际问题的,因此要和实际业务挂钩。

· 当我们拿到一个需求的时候,要对它进行分析,设计概念模式。

· 然后把概念模式转换为逻辑模式,逻辑模式转换为物理设计,最后实现数据库。

· 接下来我们一步步看这个流程。

① 需求分析

  1. 该阶段需要明确应用的流程和需要用到的信息,明确用户的信息要求处理要求安全性、完整性要求

  2. 举个例子:学生选课系统都需要些什么样的需求?学生要选课退课;老师查看自己要上的课;教务可以查看、修改所有记录等等。

② 概念设计和逻辑设计

  1. 概念和逻辑设计都是在设计数据库的概念模式,即选用一种数据模型(关系/层次/网络模型)

    数据模式(如关系模型则是表头)来描述现实世界

  2. 在概念设计的时候给出一个E-R图,阐明数据库中包含什么实体(Entity,即表名),

    以及它们之间的关系

  3. 在逻辑设计的时候给出一个数据模式(Data Schema),用DDL在DBMS中定义,需要

    依赖E-R图来定义数据库、表、内容、关系。

③ 物理设计

  1. 该阶段需要给出一个物理模式(Physical Schema),描述数据模式是如何存储在存储媒介上的,

    如数据类型,主键、外键设计,索引设计等。

概念设计:E-R图

· E-R图全称为实体-关系数据模型(Entity-Relationship Data Model)。

· 概念的三要素:实体(想保存数据的一些东西),关系(实体与实体之间),属性(实体的特征)。

实体

· 实体描述了一组具有普遍性的实际个体的组合,这组个体拥有相同的特性相同的关系相同的语义

· 相同的特性指的是,都有名字、工号等;相同的关系指的是,例如,都“属于”某个部门,这个“属于”关系是共享的;相同的语义指的是,都用“员工”来定义这些实例。

属性

· 属性是实体的某种特性,并描述了这种特性对应的实例数据

· 如上图,Employee实体就拥有四个属性。

· 值得注意的是,实体中的属性名字不能与实体名字相同

· 大部分都属性值都是被物理存储的,但某些属性值也能通过计算得到(虚拟列)。

· 属性值可以为空值

· 在E-R图中,属性一般用椭圆来表示,举个例子:

关系

· 1V1的关系,实体之间可以有一对一、一对多、多对多的关系:

一个班级只能有一个班主任;一个班级有n个学生;每个学生有多个课程。

· 三角关系

· 单独关系

· 接下来我们来看一个实际例子,某个工厂物资管理的概念模型,设计的实体有:

· 首先我们把实体及其属性图画出来:

· 然后再把各个实体的联系画出来

· 最后把属性补上去,就是完整的E-R图:

· 那这个设计的过程是否有一些技巧可取呢?当然是有的。

· 首先,我们需要考虑实体与属性划分的原则,怎么样算实体,怎么样算属性?

  1. 为了尽量简化E-R图,能作为属性对待的尽量作为属性对待

  2. 作为属性,不能再具有需要描述的性质。属性必须是不可分的数据项,不能包含其他属性。

  3. 属性不能与其他实体具有联系,只能属于自身所在的实体

E-R图的合并

· 各个局部应用所面向的问题不同,各个子系统的E-R图之间会存在许多不一致的地方,称之为冲突。

· 通过合并可以解决冲突。

· 子系统的E-R图之间的冲突主要有三类:

  1. 属性冲突,同名不同域,同属性不同单位。

  2. 命名冲突,同名异义,异名同义。

  3. 结构冲突,同一个对象抽象不同,同一个实体属性不同,实体联系不同。

E-R图的冗余删除

· 冗余的数据指的是可由基本数据导出的数据,冗余的联系是指可由其他联系导出的联系。

· 如下图中,Q2个材料构成了零件,Q1个零件构成了产品,因此做产品用了Q1*Q2个材料,但是存储了Q3,就是荣誉。

· 但也不是全部冗余都必须消除,如下面的Q4=sum(Q5),但为了方便还是保留,但每次修改Q5都要修改Q4。

逻辑设计:概念转向模型

· 接下来我们要学习,如何把E-R图变成数据库,在MySQL里就是关系数据库。

· 我们知道,E-R图由实体型实体的属性实体型之间的联系三个要素组成。

· 而关系模型的逻辑结构是一组关系模式的集合。

· 因此,将E-R图转换为关系模型,其实就是将实体型、实体的属性、实体型之间的联系转化为关系模式

· 转换的原则如下

  1. 一个实体对应一个关系模式,在关系型数据库中就是一张表。

  2. 关系的属性=实体的属性,关系的码=实体的码。

  3. 实体之间不同的联系转换方式有所区别。

实体-关系模式之间的转换

· 正如上面所说的,一个实体就是一张表,实体的属性就是关系的属性,因此:

· 然后我们转换实体间的关系。

· 假设有一个1V1的关系为班级-班主任。

  1. 可以建一个独立的关系模式,即新建一张表来存储这两个实体的关系。

  2. 或者,我们可以直接合并两个关系,即在任意一张表添加一个属性,然后用外键连起来

· 假设有一个1VN的关系为班级-学生。

  1. 同样可以建立一个独立的关系模式,即新建一张表来存储。

  2. 同样可以直接合并关系,但是注意,只能在N端加入1端的码

· 假设有一个MVN的关系为课程-学生。

在这种关系里,只能通过新建一张表才能表达这两个实体之间的关系。

· 假设有一个多实体的关系,如课程-教师-学生。

那也是只能通过新建一张表来把这三个实体联系起来。

关系模式的合并

· 关系模式的合并其实就是表的合并。目的是为了减少关系(表)的个数

· 合并的方法也是非常简单,即将其中一个表的全部属性加入到另一个表中,然后去掉其中的同义属性(可能同名也可能不同),最后适当调整一下合并后新表属性的次序

· 举个例子,下面有一张教师表和一张参考书表,它们都有一个属性是课程号,这样就存在冗余,因此我们可以合并两张表:

规范化与范式

· 关系第一范式(1NF,Normal Form),属性不可再分!即表中不能有小表。

· 除了第一范式,当然还有很多其它范式啦。我们给个定义,某一关系模式R为第n范式,可简记为R∈nNF

· 一个低一级范式的关系模式,可以通过模式分解(Schema Decomposition)转换为若干个高一级范式的关系模式的集合,这个过程称为规范化(Normalization)。

· 在详细讲解规范化之前,我们需要先学习一些前置知识。

· 首先,我们看下面这张表,它是满足1NF的,但是有可能出现一些问题。

  1. 数据冗余:大量的数据反复出现。

  2. 更新异常:如果更换系主任(Mname),那很多条数据都需要被更新。

  3. 插入异常:如果一个系(Sdept)还没有学生,那主键Sno就没办法插入。

  4. 删除异常:如果某个系的学生全都毕业了,难道要把所有数据都删掉?系主任还在的呀!

· 出现这些问题,我们就说这张表的函数依赖设计的很差。

函数依赖(Functional Dependency)

· 定义:设R(U)是一个属性集U上的关系模式,X和Y是U的子集,若对于R(U)的任意一个可能的关系r,r中不可能存在两个元组在X上的属性值相等而在Y上的属性值不等,则称“X函数确定Y”或“Y函数依赖于X”,记作X→Y

· 定义很抽象,我们来看例子。

· 描述一个学生关系,可以有学号、姓名、院系等属性。一个学号只对应一个学生,一个学生只在一个系中学习。“学号”值确定后,学生的姓名及所在系第值就被唯一确定

· 那么我们就可以写Sname=f(Sno),Sdept=f(Sno),即Sno函数决定Sname,Sno函数决定Sdept。可记作Sno→Sname,Sno→Sdept。

· 再详细一点,这个学生关系的关系模式属性集合为U={Sno,Sdept,Mname,Cno,Grade}。

· 根据现实世界已知的事实,我们知道:

  1. 一个系有若干学生,但一个学生只属于一个系,因此Sno→Sdept。

  2. 一个系只有一名系主任,因此Sdept→Mname。

  3. 一个学生可以选修多门课程,每门课程有若干学生选修,因此没有确定关系。

  4. 每个学生学习一门课程都有一个成绩,因此(Sno,Cno)→Grade。

· 画出图来就可以有:

· 对于某些特殊情况的函数依赖,我们有专门的定义:

  1. 平凡函数依赖:X→Y,Y\subsetneqX(天然成立)。

  2. 非平凡函数依赖:X→Y,Y\not\subsetneqX(有额外语义,如学号→姓名)

  3. 完全函数依赖:若X→Y,且对于任意X的一个真子集X'都有X'\not\toY,则称Y对X完全函数依赖,记为X\xrightarrow{F}Y。

  4. 部分函数依赖:若X→Y,但存在真子集X'使得X'→Y,则称Y对X部分函数依赖,记为X\xrightarrow{P}Y。

  5. 传递函数依赖:若X→Y,Y→Z,Y\not\subsetneqX,Z\not\subsetneqY,则称Z对X传递函数依赖。

· 明白了函数依赖之后,我们还要复习“码”的概念,现在我们可以用函数依赖的概念来解释各种码了。

· 候选码,我们知道,是可以唯一地标识一个元组的最小属性组,是主码的候选。用函数依赖来解释,就是所有属性完全函数依赖的属性组。假设K为关系R(U)中的一个属性组,若K5025_upno_6736.pngU,则K为候选码。

· 主码,就是从候选码中挑一个。主属性,就是任何一个候选码中的属性。非主属性,顾名思义了。全码,即整个属性组才能唯一标识一个元组。

· 举个例子,在下面这张表中,候选码就是(Sno,Cno),主码也是,主属性就是Sno,Cno,非主属性就是Sdept,Mname,Grade。

第二范式(2NF)

· 定义:一个关系满足第一范式,且每个非主属性完全依赖于任意一个候选码。

· 我们上面这张Student表很明显不满足第二范式,因为Mname和Sdept是部分依赖于主码的。

· 修正方式很简单,拆成符合第二范式的多个关系(即分成两张表)即可:

· 可以看到,第二范式其实是在消除非主属性对码的部分函数依赖

· 这下SC正常了,之前提到的数据冗余、更新异常等问题就被消解掉了,可不幸的是,这些问题转移到Dept表上了(笑死)。

· 这咋办?用第三范式修正!

第三范式(3NF)

· 定义:一个关系满足第一范式,且每一个主属性既不传递依赖于候选码,也不部分依赖于候选码

· 可以发现,定义后面的“也不部分依赖于候选码”其实是第二范式的内容,因此,一个关系满足3NF也会满足2NF。

· 根据定义,我们把Dept表再拆分:

· 可以发现,第三范式是在消除非主属性对码的传递函数依赖

· 我们再来看一个例子,一个仓库管理关系,每个管理员只管理一个仓库,每种货品可以存放在多个仓库,那么就有函数依赖如下:

· 它看上去也满足3NF,但是有点奇怪,因为主属性对其他候选码存在部分函数依赖,就像(仓库ID,货品ID)部分函数依赖于管理员ID。

· 为了消除这个问题,两位科学家(Boyee,Codd)提出来修正的第三范式(BCNF)。

· 定义:设关系模式R<U,F>满足1NF,若X→Y且Y\not\subsetneqX时(非平凡函数依赖)X必含有候选码,则该关系模式满足BCNF。

· 说点人话,就是在一个关系模式R中,若每一个决定属性集都包含候选码,则R满足BCNF。决定属性,即若X→Y,则X就是决定属性。

· 有了BCNF,可以发现,所有主属性都完全函数依赖于每个不包含它的候选码,这消除了主属性对码的部分和传递函数依赖

· 如果一个关系数据库中的所有关系模式都属于BCNF,那么在函数依赖的范畴内,它已经实现了模式的彻底分解,达到了最高的规范化程度,消除了插入和删除异常。

第四范式(4NF)

· 首先,第四范式是用来解决多值依赖的,不是用来解决函数依赖的,那么什么是多值依赖呢?

· 假设有一个关系模式如下,一门课程可由多个教师讲授,每个老师可以使用多本参考书。

· 可以看到,课程可以确定教师,也可以确定参考书,但是教师和参考书之间互不影响,这就是多值依赖。

· 定义:设R(U)是属性集U上的一个关系模式。X,Y,Z是U的子集,并且Z=U-X-Y。关系模式R(U)中多值依赖X→→Y成立,并且仅当对R(U)的任一关系r,给定的一堆(x,z)值,有一组Y的值,这组值仅仅决定于x值而与z值无关。

· 以上面的例子,一门课有一组老师负责,和参考书无关,则C→→T。同理C→→B。

· 既然多值依赖的定义是这样的,那就意味着,我们需要使用全码,即所有属性的组合,才能唯一确定一条元组

· 全码带来的缺点有很多:

  1. 数据冗余度大,有多少教师、参考书就要存多少次。

  2. 增加操作复杂:假设一门课增加一个老师,那根据这门课有多少参考书,就要插入多少次。

  3. 删除操作复杂:假设一门课去掉一本参考书,那根据这门课有多少老师,就要删除多少次。

  4. 修改操作复杂:假设一门课修改一本参考书,那根据这门课有多少老师,就要修改多少次。

· 既然多值依赖带来这么多确定,那要如何解决多值依赖呢?靠第四范式!

· 定义:限制关系模式属性之间不允许出现非平凡且非函数依赖的多值依赖。

· 在上面的例子中,我们把(课程,教师,教科书)拆成(课程,教师)和(课程,参考书)即可,虽然仍然有多值依赖C→→T,C→→B,但因为已经是两张表了,因此这是一个平凡的多值依赖,满足4NF。

总结

· 关系模式规范化步骤:

· 注意,不能说规范化程度越高的关系模式越好,必须对现实世界的实际情况和用户应用需求作进一步分析,确定一个合适的,能够反映现实世界的模式。


评论