关于数据库范式及相关问题的详解

来源:互联网 发布:众途歌厅软件 编辑:程序博客网 时间:2024/06/03 17:26

作为写的第一篇文章 加上本人水平有限 大部分是比较基础的内容 希望能通过浅显的语言让自己和大家理解相关概念

因为快临近考试 所以提前总结一下DB后半学期的相关的知识点以及做题方法 这次包含的内容主要为范式及其相关概念。

相关概念汇总:

函数依赖简单点说就是:某个属性集决定另一个属性集时,称另一属性集依赖于该属性集。

(1)数据依赖
在计算机科学中,数据依赖是指一种状态,当程序结构导致数据引用之前处理过的数据时的状态。其中最重要的是函数依赖和多值依赖。
(2)函数依赖
设X,Y是关系R的两个属性集合,当任何时刻R中的任意两个元组中的X属性值相同时,则它们的Y属性值也相同,则称X函数决定Y,或Y函数依赖于X。
(3)平凡函数依赖
当关系中属性集合Y是属性集合X的子集时(Y?X),存在函数依赖X→Y,即一组属性函数决定它的所有子集,这种函数依赖称为平凡函数依赖。
(4)非平凡函数依赖
当关系中属性集合Y不是属性集合X的子集时,存在函数依赖X→Y,则称这种函数依赖为非平凡函数依赖。
(5)完全函数依赖
设X,Y是关系R的两个属性集合,X’是X的真子集,存在X→Y,但对每一个X’都有X’!→Y,则称Y完全函数依赖于X。
(6)部分函数依赖
设X,Y是关系R的两个属性集合,存在X→Y,若X’是X的真子集,存在X’→Y,则称Y部分函数依赖于X。
(7)传递函数依赖
设X,Y,Z是关系R中互不相同的属性集合,存在X→Y(Y !→X),Y→Z,则称Z传递函数依赖于X。
(8)多值依赖
设R(U)是属性集U上的一个关系模式。X,Y,Z是U的子集,并且Z=U-X-Y。关系模式R(U)中多值依赖X→→Y成立,当且仅当对R(U)的任一关系r,给定的一对(x,z)值有一组Y的值,这组值仅仅决定于x值而与z值无关。
平凡的多值依赖与非平凡的多值依赖:
若X→→Y,而Z为空集,则称X→→Y为平凡的多值依赖;若Z不为空,则称其为非平凡的多值依赖。



------------------------------------------------------------------------------------------

范式说明

 

1.1 第一范式(1NF)无重复的列(列的原子性)

 

    所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,即所谓的原子属性(atomic),同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。

    解决方式:如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。简而言之,第一范式就是无重复的列。

     (e.g 一个人可能有多个电话 如果都存在customer 表里 phonenum 就不是不可分割的数据项, 我们需要将phonenum单独保存在另外一个表中)

 

强调:在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。


1.2 第二范式(2NF)属性完全依赖于主键 (需要由主键的全部属性来决定其他列的属性)


第二范式(2NF):如果关系模式R为第一范式,并且R中每一个非主属性完全函数依赖于R的某个候选键, 则称为第二范式。


第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键、主码。

 

例如员工信息表中加上了员工编号(emp_id)列,因为每个员工的员工编号是惟一的,因此每个员工可以被惟一区分。

简而言之,第二范式(2NF)就是非主属性完全依赖于主关键字。

 

所谓完全依赖是指不能存在仅依赖主关键字一部分的属性

解决方式:如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。

 

假定选课关系表为SelectCourse(学号, 姓名, 年龄, 课程名称, 成绩, 学分),关键字为组合关键字(学号, 课程名称),因为存在如下决定关系:

 

(学号, 课程名称) → (姓名, 年龄, 成绩, 学分)

 

这个数据库表不满足第二范式,因为存在如下决定关系:

 

(课程名称) → (学分)

 

(学号) → (姓名, 年龄)

 

即存在组合关键字中的部分字段决定非关键字的情况。

 

由于不符合2NF,这个选课关系表会存在如下问题:

 

(1) 数据冗余:

 

同一门课程由n个学生选修,"学分"就重复n-1次;同一个学生选修了m门课程,姓名和年龄就重复了m-1次。

 

(2) 更新异常:

 

若调整了某门课程的学分,数据表中所有行的"学分"值都要更新,否则会出现同一门课程学分不同的情况。

 

(3) 插入异常:

 

假设要开设一门新的课程,暂时还没有人选修。这样,由于还没有"学号"关键字,课程名称和学分也无法记录入数据库。

 

(4) 删除异常:

 

假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除。但是,与此同时,课程名称和学分信息也被删除了。很显然,这也会导致插入异常。

 

把选课关系表SelectCourse改为如下三个表:

 

学生:Student(学号, 姓名, 年龄);

 

课程:Course(课程名称, 学分);

 

选课关系:SelectCourse(学号, 课程名称, 成绩)。

 

这样的数据库表是符合第二范式的, 消除了数据冗余、更新异常、插入异常和删除异常。

 


1.3 第三范式(3NF)属性不依赖于其它非主属性 [ 消除传递依赖 ](属性列与主键直接相关而不是间接相关)

 

第三范式(3NF):如果关系模式R是第二范式,且每个非主属性都不传递依赖于R的候选键,则称R为第三范式模式。

满足第三范式(3NF)必须先满足第二范式(2NF)。第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。

 

例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在的员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。


第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。换言之,第三范式就是属性不依赖于其它非主属性。(i.e 不存在非主属性决定属性的情况)

解决方法:如果存在, 同样将该依赖关系分成两个不同的表。

 

所谓传递函数依赖,指的是如果存在"A → B → C"的决定关系,则C传递函数依赖于A。

 

因此,满足第三范式的数据库表应该不存在如下依赖关系:

 

关键字段 → 非关键字段x → 非关键字段y

 

假定学生关系表为Student(学号, 姓名, 年龄, 所在学院, 学院地点, 学院电话),关键字为单一关键字"学号",因为存在如下决定关系:

 

(学号) → (姓名, 年龄, 所在学院, 学院地点, 学院电话)

 

这个数据库是符合2NF的,但是不符合3NF,因为存在如下决定关系:

 

(学号) → (所在学院) → (学院地点, 学院电话)

 

即存在非关键字段"学院地点"、"学院电话"对关键字段"学号"的传递函数依赖。

 

它也会存在数据冗余、更新异常、插入异常和删除异常的情况,读者可自行分析得知。

 

把学生关系表分为如下两个表:

 

学生:(学号, 姓名, 年龄, 所在学院);

 

学院:(学院, 地点, 电话)。

 

这样的数据库表是符合第三范式的,消除了数据冗余、更新异常、插入异常和删除异常。


1.4 BCNF范式 在满足第三范式的基础上 消除主属性的对码的部分函数依赖与传递函数依赖

关系模式 仓库(仓库名,管理员,物品名,数量) 属于哪一级范式?

答:已知函数依赖集:仓库名 → 管理员,管理员 → 仓库名,(仓库名,物品名)→ 数量
码:(管理员,物品名),(仓库名,物品名)
主属性:仓库名、管理员、物品名
非主属性:数量
∵ 不存在非主属性对码的部分函数依赖和传递函数依赖。∴ 此关系模式属于3NF

此关系模式已经属于了 3NF,那么这个关系模式是否存在问题呢?我们来看以下几种操作:

  1. 先新增加一个仓库,但尚未存放任何物品,是否可以为该仓库指派管理员?——不可以,因为物品名也是主属性,根据实体完整性的要求,主属性不能为空。
  2. 某仓库被清空后,需要删除所有与这个仓库相关的物品存放记录,会带来什么问题?——仓库本身与管理员的信息也被随之删除了。
  3. 如果某仓库更换了管理员,会带来什么问题?——这个仓库有几条物品存放记录,就要修改多少次管理员信息。

从这里我们可以得出结论,在某些特殊情况下,即使关系模式符合 3NF 的要求,仍然存在着插入异常,修改异常与删除异常的问题,仍然不是 ”好“ 的设计。

造成此问题的原因:存在着主属性对于码的部分函数依赖与传递函数依赖。(在此例中就是存在主属性【仓库名】对于码【(管理员,物品名)】的部分函数依赖。

解决办法:就是要在 3NF 的基础上消除主属性对于码的部分与传递函数依赖。

仓库(仓库名,管理员)
库存(仓库名,物品名,数量)

这样,之前的插入异常,修改异常与删除异常的问题就被解决了。 感觉这位前辈写的比较清楚

(BCNF部分转自 作者:知乎用户 链接:https://www.zhihu.com/question/24696366/answer/29189700
来源:知乎)

      自己总结一下:
  1. 首先一个关系数据库创建出来就是符合第一范式 
  2. 第二范式消除部分依赖(所有属性完全依赖主码)
  3. 第三范式消除传递依赖(不存在非主属性决定属性的情况)
  4. BCNF消除主属性中的部分依赖和传递依赖
  5. 一般实际到BCNF或者3NF就可以了  往往允许一部分冗余存在 因为范式过高容易导致表的数目过多 
---------------------------分割线-----------------------------
相关章节中作业问题及方法的总结:
1.给一个scheme以及其对应的函数依赖集F   Q:Derive all candidate keys for this schema
简单做法是看哪些属性在F中的左边,再排除掉可以由其他属性推导出的属性
General的做法是根据:
armstrong定理 
●自反律(reflexivity):若α为为一属性集且β⊆α,则有α→β。 
●增补律(augmentation):若有α→β且λ为一属性集,则有λα→λβ。 
●传递律(transitivity):若有α→β及β→λ,则有α→λ。 
派生的规则(简化计算),可由Armstrong推导出 
●合并律(union):若有α→β及α→λ,这则有α→βλ。 
●分解律(decomposition):若有α→βλ,则有α→β及α→λ。 
●伪传递律(pseudotransitivity):若有α→β及λβ→ σ ,则有α→σ。
然后这样可以求出对应的左边的最终的属性集合就是对应的候选码

2.求最小函数依赖集/ Derive the canonical cover of the functional dependencies in F
步骤:
① 用分解的法则,使F中的任何一个函数依赖的右部仅含有一个属性;
② 去掉多余的函数依赖:从第一个函数依赖X→Y开始将其从F中去掉,然后在剩下的函数依赖中求X的闭包X+,看X+是否包含Y,若是,则去掉X→Y;否则不能去掉,依次做下去。直到找不到冗余的函数依赖; (闭包即已知X 根据X可以推导出哪些属性的集合就是X的闭包)
③去掉各依赖左部多余的属性。对于F中每一个左端包含多个属性的X->A,选择X的每个子集Z,如果A属于Z的闭包,则用Z->A代替X->A
3.判断是否属于BCNF范式
根据一堆原始属性集以及对应的函数依赖 在求出的canonical cover of F之后, 一般来说不会直接是BCNF范式 。根据求出的最小函数依赖集进行分解,叙述原因的时候写:e.g There is nontrivial functional dependency: G→AE and G is not the superkey.