前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第3篇:更新异常与规范化设计

第3篇:更新异常与规范化设计

作者头像
Spark学习技巧
发布2018-03-20 14:28:21
1.9K0
发布2018-03-20 14:28:21
举报
文章被收录于专栏:Spark学习技巧Spark学习技巧

第三篇:更新异常与规范化设计

前言

在前两篇中,主要讲了ER建模和关系建模。在具体分析如何用数据库管理软件RDBMS(Relational Database Management System)实现这些关系前,我想有必要思考下面这个问题:

问什么要这么麻烦?为什么又是ER建模又是关系建模的?

本篇的出发点就是回答这个问题。然而某种程度上,也是回答另一个本质性的问题:为什么要有数据库?

更新异常

数据库的四大操作:增,删,改,查中,除了查,其他三个都可归为更新操作。而总的来说,ER建模和关系建模的目的,就是为了避免因大量冗余数据导致的数据库更新异常。

接下来本文将使用一张旅游公司的数据表,来具体分析没有ER建模和关系建模将导致的问题。

该数据表将由以下这些列组成:

下面是该表内的一部分数据:

(字看不清的话请将图片下载到本地观看)

看到这张表的第一眼,就能发现有很多冗余数据存在,比如红框中的部分:

为什么信息冗余会导致更新异常呢?下面将对三种更新操作:插入,删除,修改可能出现的异常分别进行分析。

1. 插入异常(insertion anomaly)

这种异常是指当用户想要插入某一真实世界的实体数据时,还必须输入另一个真实世界中实体的数据。

举例来说,公司业务发展,新建了一个“家庭主妇团”的模式。但我要想往表里录入一个新的模式,还必须绑定地录入一个新的活动。

2. 删除异常(deletion anomaly)

这种异常是指当用户要删除某一真实世界的实体数据时,还必须删除另一个真实世界中实体的数据。

举例来说,假如删除下图红框中的记录:

(字看不清的话请将图片下载到本地观看)

就会导致把“老年人团”这种模式的相关数据也给清除掉了。

3. 修改异常(modification anomaly)

这种异常是指当用户要修改某个值的时候,同样的修改操作需要重复多次。

举例来说,假如公司为了吸引客户,决定多送一天,因而需要将”云南七日游“的持续时间改为8天。这时需要改动的地方就有三处了,如下图红框中所示:

函数依赖

上述的这些更新异常,都可通过规范化设计的方式避免。在详细介绍规范化设计之前,首先来讨论一个重要的概念:函数依赖(functional dependency)。

函数依赖,是指关系中每行记录的某一列(或几列)的值唯一决定该条记录另一列的值。总的来说,有以下几种函数依赖:

1. 平凡函数依赖(trivial functional dependency)

是指一个或多个属性确定它自己,或者它的子集。如本文样例数据集中TravelCampaignID,TravelCampaignName -> TravelCampaignID就是一个平凡函数依赖。

注:这种依赖在规范化中不会被用到。

2. 增广函数依赖(augmented functional dependency)

是指某个依赖式为真,则依赖式左侧,或者两侧同时增加某语句形成的一种依赖关系。如本文样例数据集中TravelCampaignID,ModleID -> TravelCampaignName。因为只需要TravelCampaignID就能够确定TravelCampaignName了。

注:这种依赖在规范化中不会被用到。

3. 等价函数依赖(equivalent functional dependency)

这种依赖关系是一对对的。比如若A->B和B->A都为真,那么A能推出来的,B同样也能推出来,因此A->B和B->A就被称作等价函数依赖。如本文样例数据集中TravelCampaignID-> TravelCampaignName和TravelCampaignName-> TravelCampaignID。

注:这种依赖只需保留一组依赖关系即可,但它不属于规范化的范畴。

4. 部分函数依赖(partial functional dependency)

是指关系的一列函数依赖于组合主码的一部分。显然这种依赖只有组合主码才存在。如本文样例数据中ModelID->ModelName,因为记录的复合主码(TravelCampaignID, ModelID)能确定记录的任何一列,ModelID只是该复合主码的一部分。

注:这种依赖关系属于规范化范畴。

5. 完全函数依赖(full key functional dependency)

是指复合主码函数确定关系中的其他列,并且复合主码的任意部分不能单独确定其他列。这个概念和上面的部分函数依赖显然是对立的。

注:这种依赖关系属于规范化范畴。

6. 传递函数依赖(transitive functional dependency)

是指非码列函数确定关系中的其他非码列。如本文样例数据中CampaignManangerID->CampaignManangerName显然就是一个传递函数依赖。

这六种函数依赖中只有后面三种和规范化设计有关。前面三种则因为对改进冗余信息并没有帮助,不纳入规范化过程中。

规范化

规范化设计能够有效的避免数据冗余导致的更新异常,它基于范式思想。一个关系是否满足某种范式通常要看它是否不包含某个函数依赖。

下面首先来看看这几个范式的定义:

1. 第一范式(1NF)

一个表如果每一行都是唯一,并且任何行都没有包含多个值的列,则它满足1NF。但对于关系表来说,真正的规范化过程从第二范式开始,因为关系表本身已经满足1NF了。

2. 第二范式(2NF)

一个表如果满足1NF,并且不包含部分函数依赖,则这个表满足2NF。

3. 第三范式(3NF)

一个表如果满足2NF,并且不包含传递函数依赖,则这个表满足3NF。

至于3NF以上的范式,则基于其他函数依赖,对于减少数据冗余消除异常没有多大帮助。这里就不再介绍了。

对样例数据进行第三范式规范化后,结果如下(红字列对应主码):

旅行活动表:

业务经理表:

游玩模式表:

旅行活动 - 游玩模式联系表:

现在请读者自行思考一下,更新异常解决了吗?答案是肯定的。但是也不能说100%的冗余信息都去除了,比如说外码的映射关系就重复了一次。

那么如果要对外码进行变更,有什么办法保证不异常呢?这部分内容将在第五篇 讲解。

规范化的例外情况

并不是说所有的关系都必须满足3NF,没有那么绝对。有些时候可以考虑降到2NF。

比如说下面这个是某公司销售经理信息表:

这张表并不满足3NF,因为邮编和城市之间存在了部分函数依赖,从而有信息冗余(见上图红框部分)。但由于该公司同一地区最多只有两名销售经理,因此冗余情况很少,规范化到3NF让表设计显得过于复杂化了。因此这种情况可以考虑不升级到3NF,让上层实现去解决冗余问题。

ER建模,关系建模与规范化设计

看到这里,它们之间的关系也就呼之欲出了。这些建模工作的作用,就是能够让设计的关系更容易满足规范化设计中的(第三)范式要求,从而减少数据冗余,消除更新异常。

在实际开发中,绝大部分情况还是按着ER建模->关系建模->物理模型建模来走。这样设计出来的表绝大部分满足第三范式,只有小部分地方需要调整一下,根据实际情况决定是选用3NF还是2NF,其中前者占大多数情况。

不按这个套路来,后果就是前文提到的那一堆更新异常。

小结

看完本文的分析,读者应该明白了前两篇所做的工作:ER建模和关系建模的根本意义所在,也应该体会到了关系数据库理论的价值。

接下来的一篇,将讲解如何具体在数据库管理软件RDBMS里创建这些表,以及如何对这些表进行增,删,改,查等操作。这些工作将使用到大名鼎鼎的SQL,它是目前最受数据分析师,数据挖掘工程师们欢迎的语言。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 浪尖聊大数据 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档