首页 > 编程知识 正文

数据库中的三大范式,bcnf范式分解

时间:2023-05-06 07:06:30 阅读:15571 作者:114

首先要理解“范例(NF )”是什么意思。 根据教材的定义,范式是“适合某一层次的关系模式集合,表示一个关系内部各属性之间联系的合理化程度”。 很难理解吧? 实际上,可以将其大致理解为一个数据表的表结构相匹配的某个设计标准的级别。 就像装修房子买建材一样,最环保的是E0级,其次是E1级,还有E2级等。 范例也分为1NF、2NF、3NF、BCNF、4NF、5NF。 一般来说,我们设计关系数据库时,最多考虑BCNF就足够了。 符合高层次范式的设计,一定符合低层次范式。 例如,如果与2NF的关系模式一致,则一定与1NF一致。

接下来说明各级的范例。 首先是第一范式(1NF )。

符合1NF的关系(请理解为数据表。 “关系模型”和“关系”之间的差异类似于面向对象编程中“类”和“对象”之间的差异。 关系是“是”关系模型的一个示例。 “关系”可以理解为带数据的表。 关系模型是此数据表的表结构。 1NF的定义是,与1NF一致的关系的各属性是不可再分割的。 表1所示情况不满足1NF的要求。

表1

事实上,1NF是所有关系数据库的最基本要求,在关系数据库管理系统(RDBMS ) (如SQL Server、Oracle和MySQL )中创建数据表时,可以设计数据表也就是说,只要是RDBMS中已经存在的数据表,就一定符合1NF。 要在RDBMS中表示表中的数据,必须将其设计为表2的格式。

表2

但是,如果只是符合1NF的设计,数据冗馀性太大,仍然存在插入异常、删除异常、修正异常的问题。 例如,对于表3设计:

表3

各学生的学号、姓名、系名、系部长等数据多次重复。 各系部长和对应系部长的数据也多次重复,——数据的冗馀性太大。 假设学校新建本科,还没有招生(如3月新设,8月再招生),就不能将系主任的数据单独添加到数据表中(注1 ),3354插入异常

注1 :由于三种关系完整性约束中的实体完整性要求,关系代码(注2 )中包含的任何属性都不能为空,也不能重复所有属性的组合。 为了满足这个要求,图中的表只把学校号码和课程名称的组合作为代码,否则就不能唯一地区分各记录。

注2 )代码)为了区分每个元组,关系中的属性或几个属性的组合(“元组”可以理解为一个表中的所有记录,即每行)。 删除某个系所有学生的相关记录,所有系和系部长的数据也会消失(并不是一个系的所有学生都不见了)。 ——消除异常个性哑铃转移到法律系后,需要修改三个记录中系和系主任的数据,以确保数据库中数据的完整性。 ——修正异常。 由于仅适用于1NF的数据库设计存在各种问题,因此需要提高设计标准,消除导致上述四个问题的因素,使之符合更高等级的范例(2NF )。 这就是所谓的“正规化”。

第二范式(2NF )关系理论中的严格定义在此不多介绍。 (因为涉及的地板很多)只需要知道2NF对1NF进行了哪些改进。 其改进在于,2NF基于1NF消除了对非主属性代码的部分函数依赖。 接下来,对与该词相关的4个概念——“函数依赖”、“代码”、“非主属性”、“部分函数依赖”进行说明。

函数依赖

在一个表中,属性(或属性组) x的值确定时,如果一定能够确定属性y的值,则y函数依赖于x,可以说是(可以理解为) X Y,但并不是特别严格的定义。 也就是说,数据表中不存在x属性(或属性组)具有相同值但y属性具有不同值的两个记录。 这也就是“函数依赖”名称的由来,类似于函数关系y=f(x )。 如果确定了x的值,则一定会确定y的值。

例如,对于表3中的数据,找不到任何记录,同一学校编号的对应名称不同。 因此,姓名函数依赖于学号,可以说是学号姓名书写。 但是相反,由于可能出现同名的学生,所以可能有不同的两个学生记录,它们的名字值相同,但对应的学校号不同,所以不能说学校号函数依赖于名字。 表中的其他函数依赖关系包括:

系名系部长学号系部长(学号、科目名)分数,但以下函数依赖关系不成立。

学号课程名学号分数课程名系主任(学号、课程名)姓名从“函数依赖”概念展开,再有三个概念。

完全函数依赖

在一张表中,在X Y中,对于x的任意一个照片子集,x’y不成立的情况下,y对x是完全函数依赖,标记为X F Y。 (那个f应该写在箭头的正上方,打不上……,正确的写法如图1所示) )。

图1

例如:

学号F姓名

(学校编号、课程名称) F分数(注:因为对应于相同学校编号的分数不确定,对应于相同课程名称的分数也不确定)一些函数是依赖的

如果y函数依赖于x而y依赖于x而不是完全函数,则y部分函数被称为依赖于x,如图2那样标记为X P Y。

图2

raph">

例如:

(学号,课名) P→ 姓名


传递函数依赖
假如 Z 函数依赖于 Y,且 Y 函数依赖于 X (感谢

@百达 指出的错误,这里改为:『Y 不包含于 X,且 X 不函数依赖于 Y』这个前提),那么我们就称 Z 传递函数依赖于 X ,记作 X T→ Z,如图3。


图3


设 K 为某表中的一个属性或属性组,若除 K 之外的所有属性都完全函数依赖于 K(这个“完全”不要漏了),那么我们称 K 为候选码,简称为码。在实际中我们通常可以理解为:假如当 K 确定的情况下,该表除 K 之外的所有属性的值也就随之确定,那么 K 就是码。一张表中可以有超过一个码。(实际应用中为了方便,通常选择其中的一个码作为主码)

例如:
对于表3,(学号、课名)这个属性组就是码。该表中有且仅有这一个码。(假设所有课没有重名的情况)

非主属性
包含在任何一个码中的属性成为主属性。

例如:
对于表3,主属性就有两个,学号 与 课名。


终于可以回过来看2NF了。首先,我们需要判断,表3是否符合2NF的要求?根据2NF的定义,判断的依据实际上就是看数据表中是否存在非主属性对于码的部分函数依赖。若存在,则数据表最高只符合1NF的要求,若不存在,则符合2NF的要求。判断的方法是:

第一步:找出数据表中所有的码。
第二步:根据第一步所得到的码,找出所有的主属性。
第三步:数据表中,除去所有的主属性,剩下的就都是非主属性了。
第四步:查看是否存在非主属性对码的部分函数依赖。

对于表3,根据前面所说的四步,我们可以这么做:

第一步:

查看所有每一单个属性,当它的值确定了,是否剩下的所有属性值都能确定。查看所有包含有两个属性的属性组,当它的值确定了,是否剩下的所有属性值都能确定。……查看所有包含了六个属性,也就是所有属性的属性组,当它的值确定了,是否剩下的所有属性值都能确定。

看起来很麻烦是吧,但是这里有一个诀窍,就是假如A是码,那么所有包含了A的属性组,如(A,B)、(A,C)、(A,B,C)等等,都不是码了(因为作为码的要求里有一个“完全函数依赖”)。

图4表示了表中所有的函数依赖关系:

图4

这一步完成以后,可以得到,表3的码只有一个,就是(学号、课名)。

第二步:
主属性有两个:学号 与 课名


第三步:
非主属性有四个:姓名、系名、系主任、分数


第四步:
对于(学号,课名) → 姓名,有 学号 → 姓名,存在非主属性 姓名 对码(学号,课名)的部分函数依赖。
对于(学号,课名) → 系名,有 学号 → 系名,存在非主属性 系名 对码(学号,课名)的部分函数依赖。
对于(学号,课名) → 系主任,有 学号 → 系主任,存在非主属性 对码(学号,课名)的部分函数依赖。

所以表3存在非主属性对于码的部分函数依赖,最高只符合1NF的要求,不符合2NF的要求。



为了让表3符合2NF的要求,我们必须消除这些部分函数依赖,只有一个办法,就是将大数据表拆分成两个或者更多个更小的数据表,在拆分的过程中,要达到更高一级范式的要求,这个过程叫做”模式分解“。模式分解的方法不是唯一的,以下是其中一种方法:
选课(学号,课名,分数)
学生(学号,姓名,系名,系主任)

我们先来判断以下,选课表与学生表,是否符合了2NF的要求?

对于选课表,其码是(学号,课名),主属性是学号和课名,非主属性是分数,学号确定,并不能唯一确定分数,课名确定,也不能唯一确定分数,所以不存在非主属性分数对于码 (学号,课名)的部分函数依赖,所以此表符合2NF的要求。

对于学生表,其码是学号,主属性是学号,非主属性是姓名、系名和系主任,因为码只有一个属性,所以不可能存在非主属性对于码 的部分函数依赖,所以此表符合2NF的要求。

图5表示了模式分解以后的新的函数依赖关系

图5

表4表示了模式分解以后新的数据


表4

(这里还涉及到一个如何进行模式分解才是正确的知识点,先不介绍了)

现在我们来看一下,进行同样的操作,是否还存在着之前的那些问题?

个性的哑铃转系到法律系
只需要修改一次个性的哑铃对应的系的值即可。——有改进数据冗余是否减少了?
学生的姓名、系名与系主任,不再像之前一样重复那么多次了。——有改进删除某个系中所有的学生记录
该系的信息仍然全部丢失。——无改进插入一个尚无学生的新系的信息。
因为学生表的码是学号,不能为空,所以此操作不被允许。——无改进

所以说,仅仅符合2NF的要求,很多情况下还是不够的,而出现问题的原因,在于仍然存在非主属性系主任对于码学号的传递函数依赖。为了能进一步解决这些问题,我们还需要将符合2NF要求的数据表改进为符合3NF的要求。

第三范式(3NF) 3NF在2NF的基础之上,消除了非主属性对于码的传递函数依赖。也就是说, 如果存在非主属性对于码的传递函数依赖,则不符合3NF的要求。

接下来我们看看表4中的设计,是否符合3NF的要求。

对于选课表,主码为(学号,课名),主属性为学号和课名,非主属性只有一个,为分数,不可能存在传递函数依赖,所以选课表的设计,符合3NF的要求。

对于学生表,主码为学号,主属性为学号,非主属性为姓名、系名和系主任。因为 学号 → 系名,同时 系名 → 系主任,所以存在非主属性系主任对于码学号的传递函数依赖,所以学生表的设计,不符合3NF的要求。。

为了让数据表设计达到3NF,我们必须进一步进行模式分解为以下形式:
选课(学号,课名,分数)
学生(学号,姓名,系名)
系(系名,系主任)

对于选课表,符合3NF的要求,之前已经分析过了。

对于学生表,码为学号,主属性为学号,非主属性为系名,不可能存在非主属性对于码的传递函数依赖,所以符合3NF的要求。

对于系表,码为系名,主属性为系名,非主属性为系主任,不可能存在非主属性对于码的传递函数依赖(至少要有三个属性才可能存在传递函数依赖关系),所以符合3NF的要求。。


新的函数依赖关系如图6

图6

新的数据表如表5


表5


现在我们来看一下,进行同样的操作,是否还存在着之前的那些问题?

删除某个系中所有的学生记录
该系的信息不会丢失。——有改进插入一个尚无学生的新系的信息。
因为系表与学生表目前是独立的两张表,所以不影响。——有改进数据冗余更加少了。——有改进


结论
由此可见,符合3NF要求的数据库设计,基本上解决了数据冗余过大,插入异常,修改异常,删除异常的问题。当然,在实际中,往往为了性能上或者应对扩展的需要,经常 做到2NF或者1NF,但是作为数据库设计人员,至少应该知道,3NF的要求是怎样的。

==============时隔半年,终于决定把这个坑填上,来晚了 ===========

BCNF范式

要了解 BCNF 范式,那么先看这样一个问题:

若:

某公司有若干个仓库;
每个仓库只能有一名管理员,一名管理员只能在一个仓库中工作;
一个仓库中可以存放多种物品,一种物品也可以存放在不同的仓库中。每种物品在每个仓库中都有对应的数量。

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

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

基于此关系模式的关系(具体的数据)可能如图所示:



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

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

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

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

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

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

这样,之前的插入异常,修改异常与删除异常的问题就被解决了。

以上就是关于 BCNF 的解释。


最近身体不太舒服,写不动了。有空再放几个典型习题及其解答吧。
===============================
问题1:

lsdxz :老师您好,我看了您关于数据库范式的回答,有一点不太理解,就是关于码的定义,如果除K之外的所有属性都完全函数依赖于K时才能称K为码,那么在判断2NF时又怎么会存在非主属性对码的部分函数依赖这种情况?希望老师有时间能指点一下,谢谢

我 :在“码”的定义中,除 K 之外的所有属性应该看成是一个集合 U(也就是一个整体),也就是说,只有 K 能够完全函数决定 U 中的每一个属性,那么 K 才是码。如果 K 只是能够完全函数决定 U 中的一部分属性,而不能完全函数决定另外一部分属性,那么 K 不是码。

比如有关系模式 R (Sno, Sname, Cno, Cname, Sdept, Sloc, Grade),其中函数依赖集为 F= {
Sno → Sname, Sno → Sdept, Sdept → Sloc,Sno → Sloc, Cno → Cname, (Sno, Cno) → Grade }

那么 R 中的码只能是 (Sno, Cno),Sno 或 Cno 并不能完全函数决定除 Sno / Cno 之外的所有其他属性(其实就是不能决定 Grade ),所以单独的 Sno 与 Cno 并不能作为码。

所以可得到主属性:Sno, Cno
非主属性:Sname, Cname, Sdept, Sloc, Grade

R 中存在非主属性 Cname 对于码 (Sno, Cno) 的部分函数依赖 (Cno → Cname) 。(还有很多别的例子就不一一列举了)。所以 R 不符合 2NF 的要求。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。