常见设计范式
了解范式之前,必须准备的知识点
百科百科提供了“范式”的名词解释:范式是符合某一种级别的关系模式的集合。关系数据库中的关系必须满足一定的要求,满足不同程度要求的为不同范式。
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、Boyce-Codd范式(BCNF)、第四范式(4NF)和第五范式(5NF)。
满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了。
只根据上面的三句话,对于完全未接触过数据库设计的孩子来说,实在是有点摸不着重点,更不要说如何实现到自己的项目中去。
思考几个关于数据库使用的问题
- 数据库中有没有出现过一张表中出现大量的重复数据的列?
- 数据库中有没有出现如果要删除一条数据,结果改条数据中存在其他不能删除的数据?
- 数据库中有没有在要进行数据更新时导致大批量更新操作?
- 数据库使用查询时无法准确定位?
部分名词解释
在将范式之前,我们需要先了解一些后面会用到的名词,以便于下面知识点的理解。
函数依赖
周星驰在《唐伯虎点秋香中》进入华府时,大家都不认识他,主管给了他一个编号为 9527,大家每次要找他的时候,只需要喊9527,就知道是在喊他。
此时,9527 和 剧中的周星驰就有了联系,在编号值确定是 9527 的情况下,必定能确定是唐伯虎,那么就可以说 唐伯虎 函数依赖于9527,写作 唐伯虎 → 9527。
抽象化一下,我们再说一遍:当一张数据库表中,X 确定的情况下,必定能确定 Y,那么就可以说,Y函数依赖于X,记作 X → Y 。
这个知识点是基础,请记住。
完全函数依赖
回到现实中,我在东风公司的时候,进公司时,也为我设置了员工编号103429,在后来的工作中,我在很多部门都担有职务,如:团支部组织委员、单身委员会文体兼宣传委员、4I课题组组长、研发部研发工程师、足球队队员等。
确认编号103429时,就能确认是我,记作 103429 → 杨洋。
确认**(编号103429,组织委员)→ 组织活动**。
但是如果只确认编号103429,无法确定我的工作,只确认组织委员,也无法确认哪个工作(注:四个车间有四个团支部,也就有四个组织委员,工作可能不同 )。
这种 103429 → 杨洋 / (编号103429,组织委员)→ 组织活动 一对一 的强关联关系 就是完全函数依赖。
抽象化一下,我们再说一遍:对于 X 的任何一个真子集(假如属性组 X 包含超过一个属性的话),X → Y 不成立,那么我们称 Y 对于 X 完全函数依赖。
注:解释为(X1,X2)→ Y 成立,X1 → Y不成立,X2 → Y不成立。
部分函数依赖
因为我身兼多职,所以很多部门都会有我的名字。
如 (编号103429,团支部)→ 杨洋,(编号103429,单身委员会)→ 杨洋。
我依赖于真子集,但是不完全函数依赖于 真子集。
抽象化一下,我们再说一遍:假如 Y 函数依赖于 X,但同时 Y 并不完全函数依赖于 X,那么我们就称 Y 部分函数依赖于 X,记作 X P→ Y
传递函数依赖
以团支部为例,组织委员 函数依赖于 团支部,团支部 函数依赖于 总装车间。(每个车间都有团支部,如冲压、涂装、总装、营销等 )
抽象化一下,我们再说一遍:假如 Z 函数依赖于 Y,且 Y 函数依赖于 X,那么我们就称 Z 传递函数依赖于 X ,记作 X T→ Z
码(主键)
当 K 确定的情况下,该表除 K 之外的所有属性的值也就随之确定,那么 K 就是码。一张表中可以有超过一个码。(实际应用中为了方便,通常选择其中的一个码作为主码)
这里所说的码,在表应用中可以理解为 唯一索引。
一张表中设置了唯一索引,那么这条数据在表中一定是唯一的,也可以通过唯一索引找到唯一的这一条数据。
非主属性
不包含在任何一个码中的属性成为主属性。
结合上面的信息,理解为除了唯一索引之外的字段。
第一范式
1NF的解释
准备工作已经到位,接下来我们来讲范式。
1NF的定义为:符合1NF的关系中的每个属性都不可再分。
所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。
简单说来就是在设计数据库表时,根据实际的业务需求,设计好字段,每个字段不重复即可。
实例讲解
以上面我的例子为业务,设计一张表则可以得到以下符合第一范式的表:
表1
1NF是所有关系型数据库的最基本要求,从上面这张表就能看出一些明显的问题点:
- 重复数据过多–数据冗余过大
- 单独新建一个部门(还未设置人员的时候),无法完成数据插入
- 加入我要从总装换到涂装,则需要修改我的所有数据,但我却不是涂装研发部的人或者足球队的前锋。
- 如果我要删除张三的数据,那么表中涂装相关的数据也没有了,但是没有数据不代表没有涂装这个车间和部门
第二范式
2NF的解释
2NF在1NF的基础之上,消除了非主属性对于码的部分函数依赖。
第二范式(2NF)要求数据库表中的每个实例或行必须可以被唯一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。这个唯一属性列被称为主关键字或主键、主码。
简而言之,第二范式就是非主属性完全依赖于唯一索引。
实例讲解
第一步:找出数据表中所有的码。
第二步:根据第一步所得到的码,找出所有的主属性。
第三步:数据表中,除去所有的主属性,剩下的就都是非主属性了。
第四步:查看是否存在非主属性对码的部分函数依赖。
表1中的问题我们上面已经分析过了,现在要做的就是消除非主属性对于码的部分函数依赖。
第一步:(编号,职务)为这个表的码(唯一索引),
第二步:(编号,职务)为主属性
第三步:姓名、车间、主任、工作 为非主属性
第四步:
对于(编号,职务) → 姓名,有 编号 → 姓名,存在非主属性 姓名 对码(编号,部门)的部分函数依赖。
对于(编号,职务) → 姓名,有 编号 → 车间,存在非主属性 车间 对码(编号,部门)的部分函数依赖。
对于(编号,职务) → 姓名,有 编号 → 主任,存在非主属性 主任 对码(编号,部门)的部分函数依赖。
其他的非主属性,无法单从 编号 或者 部门 来进行 函数依赖。
所以现在对表进行分解
表2 人员信息表
表3 职务表
通过分表,得到两张表(表2:人员信息表、表3:职务表)
再来看问题:
- 更改张三的归属车间,只需要修改一条数据即可
- 人员下信息表,每天数据只出现一次,冗余数据减少
- 删除张三的信息,所对应的车间信息也会删除,无改进
- 新增一条新车间信息,无人员的情况下,无法新增
所以根据以上的表结构,只能满足2NF的需求
主要问题在于,非主属性 主任 函数依赖于 车间 ,传递函数依赖于 编号。
第三范式
3NF的解释
3NF在2NF的基础之上,消除了非主属性对于码的传递函数依赖。
简而言之,第三范式就是属性不依赖于其它非主属性。
实例讲解
表2 人员信息表 主码为编号,主属性为编号,非主属性为姓名、车间和主任。因为 编号 → 车间,同时 车间 → 主任,所以存在非主属性系主任对于码编号的传递函数依赖,所以人员信息表的设计,不符合3NF的要求。
表3 职务表 主码为(编号,职务),主属性为 编号 和 职务 ,非主属性只有一个,为工作,不可能存在传递函数依赖,所以职务表的设计,符合3NF的要求。
对 人员信息表 分解
现在再来看看问题:
- 删除张三,涂装车间的信息也能保留
- 新增一个新车间,插入也能成功
由此可见,符合3NF要求的数据库设计,基本上解决了数据冗余过大,插入异常,修改异常,删除异常的问题。
总结一下
1NF的定义为:符合1NF的关系中的每个属性都不可再分。
2NF在1NF的基础之上,消除了非主属性对于码的部分函数依赖。
3NF在2NF的基础之上,消除了非主属性对于码的传递函数依赖。