数据库理论 —— 数据库设计六大范式
Posted 扫地增
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库理论 —— 数据库设计六大范式相关的知识,希望对你有一定的参考价值。
前言
笔者遇到范式是在数据仓库建模时,以前对范式的理解比较浅显,且只了解前三范式,对后面三个范式并不了解,趁此机会和大家一起把其他范式学习下。
1. 基础概念
在了解范式之前我们需要对其中的一些基本概念进行了解。
1.1 候选码
某一属性组的值能唯一标识一个元组,而其子集不能,则称该属性组为候选码。若一个关系中有多个候选码,则选定其中一个为主码。
例如下图所示的学生表中,学号和姓名都可以唯一标识一个元组,故该表的候选码为学号和姓名,我们可以随便选定其中一个作为主码。
1.2 主属性
所有候选码的属性称为主属性。不包含在任何候选码中的属性称为非主属性或非码属性
在上面的学生表中,学号和姓名就是该关系的主属性,年龄和性别就是非主属性。
1.3 函数依赖
设R为任一给定的关系,如果对于R中属性X的每一个值,R中的属性Y只有唯一值与之对应,则称X函数决定Y或Y函数依赖于X,记作X——>Y。其中X称为决定因素。
通俗一点,就是给定一个X都有唯一的Y。可以理解为函数y=f(x);对于 任意的x 都有一个y,且y的取值有x决定。
例如:学号可以唯一确定一个学生的年龄、姓名等信息。
1.4 完全函数依赖
如果存在 X 属性组(注意是组,说明是联合主键)决定 唯一的 Y ,但 X 中的任一子集却不能决定唯一的 Y,则 Y 完全依赖于 X。
例如:学生的成绩由学生与课程共同决定。所以成绩完全依赖于学生与课程。
1.5 部分函数依赖
与完全函数依赖相反:如果存在 X 属性组(注意是组,说明是联合主键)决定 唯一的 Y ,且 X 中的任一子集都能能决定唯一的 Y,则 Y 部分依赖于X。
例如:在没有同名的情况下,学号与姓名都可以决定一个学生的年龄、性别等信息。
1.6 传递函数依赖
设 R 为任一给定关系, X Y Z 为其不同的属性子集,若 X —> Y 且 Y —>Z,则有 X —>Z,称为 Z 传递函数依赖于 X
例如:学号可以唯一确定一个系部,且系部可以唯一确定一个系主任。
2. 范式
2.1 什么是范式?
范式来自英文Normal form
,简称NF
。要想设计—个好的关系,必须使关系满足一定的约束条件,此约束已经形成了规范,这就是我们俗称的范式。范式分成几个等级,一级比一级要求得严格。各种范式呈递次规范,越高的范式数据库冗余越小。在设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,没有冗余的数据库未必是最好的数据库, 有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。
2.2 范式的分类
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)
。各范式之间的联系如下:
如下图所示:
满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了。
2.2.1 第一范式(1NF)(针对具体某一列)
所谓第一范式(1NF)是指在关系模型中,对域添加的一个规范要求,所有的域都应该是原子性的,即数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,记录等非原子数据项。即实体中的某个属性有多个值时,必须拆分为不同的属性。在符合第一范式(1NF)表中的每个域值只能是实体的一个属性或一个属性的一部分。简而言之,第一范式就是无重复的域。
- 不符合:
- 符合:
实例:
例:下面这个表中张三其实是一个人,如果在一个java程序中应该是一个实体类,但是在数据库中记录成两条记录,因为tel列中包含了手机和宅电两个属性。
id | name | tel |
---|---|---|
1 | 张三 | 18656565656 |
2 | 张三 | 36522323 |
正确的方式是下面这样
id | name | tel | phone |
---|---|---|---|
1 | 张三 | 36522323 | 18656565656 |
2.2.2 第二范式( 2NF )(针对某一列与复合主键的一部分有关)
- 定义:
所谓第二范式,是指所有的非主属性都完全依赖于关键字。 - 理解:
第二范式必须满足第一范式。
第二范式是指每个关系必须有一个(有且仅有一个)数据项作为主键,其他数据项与主键一一对应,即其他数据项完全依赖于主键。由此可知单主属性的关系均属于第二范式。 - 判断一个范式是否符合第二范式
实例:
例:假定选课关系表为SelectCourse(学号,姓名,年龄,课程名称,成绩,学分),关键字为组合关键字(学号,课程名称),因为存在如下决定关系:
stuId | name | age | kemu | score | xuefen |
---|---|---|---|---|---|
1 | 张三 | 16 | 数学 | 89 | 100 |
2 | 张三 | 16 | 语言 | 90 | 100 |
age、name是由stuId决定的,与kemu无关;xuefen是由kemu决定的,与stuId无关;score是由stuId和kumu共决定的;即存在组合关键字中的字段决定非关键字的情况。由于不符合2NF,这个选课关系表会存在如下问题:
- 数据冗余:
同一门课程由n个学生选修,"学分"就重复n-1次;同一个学生选修了m门课程,姓名和年龄就重复了m-1次。 - 更新异常:
若调整了某门课程的学分,数据表中所有行的"学分"值都要更新,否则会出现同一门课程学分不同的情况。 - 插入异常:
假设要开设一门新的课程,暂时还没有人选修。这样,由于还没有"学号"关键字,课程名称和学分也无法记录入数据库。 - 删除异常:
假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除。但是,与此同时,课程名称和学分信息也被删除了。很显然,这也会导致插入异常。
把选课关系表SelectCourse改为如下三个表:
学生:Student(学号,姓名,年龄);
课程:Course(课程名称,学分);
选课关系:SelectCourse(学号,课程名称,成绩)。
这样的数据库表是符合第二范式的, 消除了数据冗余、更新异常、插入异常和删除异常。
另外,所有单关键字的数据库表都符合第二范式,因为不可能存在组合关键字。
2.2.3 第三范式(3NF)(针对某一列与主键无关,但是与某一非主键列有关)
- 定义:
每一个非主属性既不部分依赖于也不传递依赖于关键字,也就是在第二范式的基础上消除传递依赖(A>B>C)。 - 理解:
即在第二范式的基础上,消除了非主属性对码的传递依赖。
实例:
例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。
2.2.4 BCNF(针对某一列与复合主键中的某一列有关,而与其他主键无关)
- 定义:
BCNF,是指在第三范式的基础上进一步消除主属性对于码的部分函数依赖和传递依赖。BCNF需要符合3NF,并且,主属性不依赖于主属性。所有属性都完全依赖于码,每一个决定因素都包含码。 - 理解: 一个满足BC范式的关系模式有:
- 所有非主属性对每一个码都是完全函数依赖;
- 所有主属性对每一个不包含它的码也是完全函数依赖;
- 没有任何属性完全函数依赖于非码的任何一组属性。
例如有关系模式C(Cno, Cname, Pcno),Cno, Cname, Pcno依次表示课程号、课程名、先修课。可知关系C只有一个码Cno,且没有任何属性对Cno部分函数依赖或传递函数依赖,所以关系C属于第三范式,同时Cno是C中的唯一决定因素,所以C也属于BC范式。
实例:
假设仓库管理关系表为StorehouseManage(仓库ID,存储物品ID,管理员ID,数量),且有一个管理员只在一个仓库工作;一个仓库可以存储多种物品。这个数据库表中存在如下决定关系:
(仓库ID,存储物品ID) →(管理员ID,数量)
(管理员ID,存储物品ID) → (仓库ID,数量)
所以,(仓库ID,存储物品ID)和(管理员ID,存储物品ID)都是StorehouseManage的候选关键字,表中的唯一非关键字段为数量,它是符合第三范式的。但是,由于存在如下决定关系:
(仓库ID) → (管理员ID)
(管理员ID) → (仓库ID)
即存在关键字段决定关键字段的情况,所以其不符合BCNF范式。它会出现如下异常情况:
- 删除异常:
当仓库被清空后,所有"存储物品ID"和"数量"信息被删除的同时,"仓库ID"和"管理员ID"信息也被删除了。 - 插入异常:
当仓库没有存储任何物品时,无法给仓库分配管理员。 - 更新异常:
如果仓库换了管理员,则表中所有行的管理员ID都要修改。
把仓库管理关系表分解为二个关系表:
仓库管理:StorehouseManage(仓库ID,管理员ID);
仓库:Storehouse(仓库ID,存储物品ID,数量)。
这样的数据库表是符合BCNF范式的,消除了删除异常、插入异常和更新异常。
又如,有这样一个配件管理表WPE(WNO,PNO,ENO,QNT),其中WNO表示仓库号,PNO表示配件号,ENO表示职工号,QNT表示数量。
有以下约束要求:
-
一个仓库有多名职工;
-
一个职工仅在一个仓库工作;
-
每个仓库里一种型号的配件由专人负责,但一个人可以管理几种配件;
-
同一种型号的配件可以分放在几个仓库中。
分析表中的函数依赖关系,可以得到:
-
(ENO)->WNO;
-
(WNO,PNO)->QNT
-
(WNO,PNO)->ENO
-
(ENO,PNO)->QNT
可以看到,候选键有:(ENO,PNO);(WNO,PNO)。所以,ENO,PNO,WNO均为主属性,QNT为非主属性。显然,非主属性是直接依赖于候选键的。所以此表满足第三范式。
而我们观察一下主属性:(WNO,PNO)->ENO;ENO->WNO。显然WNO对于候选键(WNO,PNO)存在传递依赖,所以不符合BCNF.
解决这个问题的办法是分拆为两个表:管理表EP(ENO,PNO,QNT);工作表EW(ENO,WNO)。但这样做会导致函数依赖(WNO,PNO)->ENO丢失。
虽然,不满足BCNF,也会导致一些冗余和一致性的问题。但是,将表分解成满足BCNF的表又可能丢失一些函数依赖。所以,一般情况下不会强制要求关系表要满足BCNF。
2.2.5 4NF(第四范式)
- 定义:
第四范式,从理论层面来讲是,关系模式R∈1NF,如果对于R对于R的每个非平凡多值依赖X→→Y(Y不属于X),X都含有候选码,则R∈4NF。4NF就是限制关系模式的属性之间不允许有非平凡且非函数依赖的多值依赖。显然一个关系模式是4NF,则必为BCNF。 - 理解:
显然一个关系模式是4NF,则必为BCNF。也就是说,当一个表中的非主属性互相独立时(3NF),这些非主属性不应该有多值,若有多值就违反了4NF。
实例:
有这样一个用户联系方式表TELEPHONE(CUSTOMERID,PHONE,CELL)。CUSTOMERID为用户ID,PHONE为用户的固定电话,CELL为用户的移动电话。
本来,这是一个非常简单的第3范式表。主键为CUSTOMERID,不存在传递依赖。但在某些情况下,这样的表还是不合理的。比如说,用户有两个固定电话,两个移动电话。这时,表的具体表示如下:
CUSTOMERID | PHONE | CELL |
---|---|---|
1000 | 8828-1234 | 149088888888 |
1000 | 8838-1234 | 149099999999 |
由于PHONE和CELL是互相独立的,而有些用户又有两个和多个值。这时此表就违反第四范式。
在这种情况下,此表的设计就会带来很多维护上的麻烦。例如,如果用户放弃第一行的固定电话和第二行的移动电话,那么这两行会合并吗?等等
解决问题的方法为,设计一个新表NEW_PHONE(CUSTOMERID,NUMBER,TYPE).这样就可以对每个用户处理不同类型的多个电话号码,而不会违反第四范式。
显然,第四范式的应用范围比较小,因为只有在某些特殊情况下,要考虑将表规范到第四范式。所以在实际应用中,一般不要求表满足第四范式。
2.2.6 5NF(第五范式)
-
第五范式(5NF):是最终范式。消除了4NF中的连接依赖。
-
第五范式有以下要求:
- 必须满足第四范式
- 表必须可以分解为较小的表,除非那些表在逻辑上拥有与原始表相同的主键。
第五范式是在第四范式的基础上做的进一步规范化。第四范式处理的是相互独立的多值情况,而第五范式则处理相互依赖的多值情况。
实例:
有一个销售信息表SALES(SALEPERSON,VENDOR,PRODUCT)。SALEPERSON代表销售人员,VENDOR代表供和商,PRODUCT则代表产品。
在某些情况下,这个表中会产生一些冗余。可以将表分解为PERSON_VENDOR表(SALEPERSON,VENDOR);PERSON_PRODUCT表(SALEPERSON,PRODUCT);
VENDOR_PRODICT表(VENDOR,PRODUCT)
以上是关于数据库理论 —— 数据库设计六大范式的主要内容,如果未能解决你的问题,请参考以下文章