基于数据库范式的一点点想法
设有关系模式r<u,f>,其中u = {a,b,c,d,e},f={a→d,ce→d,bc→d,dc→a},试求:
1.求出r的所有候选关键字
一、从关系模式到函数依赖到现实模型
数学可以看作是现实世界的高度抽象,所以当我们初次看到ce→d这样的依赖时,可能会无法理解,但如果我们把它转化为现实世界中的关系模型又会如何呢,比如这样:
(学生,课程)→老师
(学生,老师)→课程
我们很容易就可以看出这个模型的意义,学生和课程可以确认一位老师,而学生和老师又可以确认一门课程,那么什么是候选键呢,我之前还只会一些浅显的sql语句时,把它同主键等同起来,当然,这导致我以后在做关系模式的题时,屡屡出错,而弄清这些模型必要的概念,更是搞懂范式的意义的关键。
回到现实背景来,关系模式(学生,老师,课程) 其中每一个老师只教一门课,每门课有若干老师,某一学生选一门课就对应一个老师。这样的又如何与抽象的数学符号组成的关系模式来对比学习呢?不如我们先假设我们现在要根据这个模式开发一个table,那么学生老师课程中,谁做主键比较合适呢,没错,你很快就会发现问题,这三个属性似乎只能以组合的形式才能唯一确定所有属性,比如你并不能以学生作为主属性,而唯一确定老师和课程,而通过(学生,老师)或(学生,课程)却能把这三个关系牢牢的联系在一起,所以说这就是候选码的意义,以候选码为圆心使所有属性联系在一起,而所谓主属性正是候选码里的属性值,是属于关系。那么第1题也就有了答案,以哪个或那几个抽象数学符号可以通过函数依赖关系联系起来u中所有元素?显然,答案是bce。
2.试将r分解为bcnf,并具有无损连接性
二、由关系模式分解到合理设计e-r图到大型项目中的数据库关系启发
事实上,合理设计,或者设计合理的数据库是很难的,比如你要开发一个管理系统,期间纠缠的各种属性单纯用脑子理好像是那么回事,但当把它实现出来时,你会发现一团乱麻,范式的意义就在这,把你从几十上百个属性中理清正确的关系,才能做后续的开发,我甚至私认为,一个项目最最重要的,就是数据库的合理设计,这是现在常说的模块化开发的前提,mvc开发的基本思想就是模块化,甚至微服务都是模块化,而什么决定了模块化?正是范式。
比如这一问,让你从这些复杂的依赖中,分解出bcnf范式,就如同让你从管理系统各种各样的似是而非的对应属性之间理出清楚的模块去开发一样,那么,什么是bcnf?如那个学生老师例子,可以明显看出它是符合3nf的(事实上,所有元素都是主属性的关系确实都可以达到3nf)既然,已经到了3nf这一较好的范式水准,为何还要继续尝试,这得谈谈bcnf优于3nf的地方,bcnf意味着在关系模式中每一个决定因素都包含候选键,也就是说,只要属性或属性组a能够决定任何一个属性b,则a的子集中必须有候选键。bcnf范式排除了任何属性(不光是非主属性,2nf和3nf所限制的都是非主属性)对候选键的传递依赖与部分依赖。假设仓库管理关系表为storehousemanage(仓库id, 存储物品id, 管理员id, 数量),且有一个管理员只在一个仓库工作;一个仓库可以存储多种物品。这个数据库表中存在如下决定关系:
(仓库id, 存储物品id) →(管理员id, 数量)
(管理员id, 存储物品id) → (仓库id, 数量)
所以,(仓库id, 存储物品id)和(管理员id, 存储物品id)都是storehousemanage的候选关键字,表中的唯一非关键字段为数量,它是符合第三范式的。但是,由于存在如下决定关系:
(仓库id) → (管理员id)
(管理员id) → (仓库id)
仓库i是决定因素,但仓库id不包含候选键(candidate key,也就是候选码,简称码)。
同样的,管理员id也是决定因素,但不包含候选键。
所以该表不满足bcnf。
我们可以得出3nf的缺点为
"存在主属性对候选关键字的传递依赖,同样也会带来麻烦。"
这里也有一个很好的例子,是从别人的博客里看来的
配件管理关系模式 wpe(wno,pno,eno,qnt)分别表仓库号,配件号,职工号,数量。有以下条件
a.一个仓库有多个职工。
b.一个职工仅在一个仓库工作。
c.每个仓库里一种型号的配件由专人负责,但一个人可以管理几种配件。
d.同一种型号的配件可以分放在几个仓库中。
分析:由以上得 pno 不能确定qnt,由组合属性(wno,pno)来决定,存在函数依赖(wno,pno) -> eno。由于每个仓库里的一种配件由专人负责,而一个人可以管理几种配件,所以有组合属性(wno,pno)才能确定负责人,有(wno,pno)-> eno。因为 一个职工仅在一个仓库工作,有eno -> wno。由于每个仓库里的一种配件由专人负责,而一个职工仅在一个仓库工作,有 (eno,pno)-> qnt。
找一下候选关键字,因为(wno,pno) -> qnt,(wno,pno)-> eno ,因此 (wno,pno)可以决定整个元组,是一个候选关键字。根据eno->wno,(eno,pno)->qnt,故(eno,pno)也能决定整个元组,为另一个候选关键字。属性eno,wno,pno 均为主属性,只有一个非主属性qnt。它对任何一个候选关键字都是完全函数依赖的,并且是直接依赖,所以该关系模式是3nf。
分析一下主属性。因为eno->wno,主属性eno是wno的决定因素,但是它本身不是关键字,只是组合关键字的一部分。这就造成主属性wno对另外一个候选关键字(eno,pno)的部 分依赖,因为(eno,pno)-> eno但反过来不成立,而p->wno,故(eno,pno)-> wno 也是传递依赖。
虽然没有非主属性对候选关键辽的传递依赖,但存在主属性对候选关键字的传递依赖,同样也会带来麻烦。如一个新职工分配到仓库工作,但暂时处于实习阶段,没有独立负责对某些配件的管理任务。由于缺少关键字的一部分pno而无法插入到该关系中去。又如某个人改成不管配件了去负责安全,则在删除配件的同时该职工也会被删除。
解决办法:分成管理ep(eno,pno,qnt),关键字是(eno,pno)工作ew(eno,wno)其关键字是eno
缺点:分解后函数依赖的保持性较差。如此例中,由于分解,函数依赖(wno,pno)-> eno 丢失了, 因而对原来的语义有所破坏。没有体现出每个仓库里一种部件由专人负责。有可能出现 一部件由两个人或两个以上的人来同时管理。因此,分解之后的关系模式降低了部分完整性约束。
那么看了这么多例子,即分解为bcnf的首要即是不对原关系(语意)进行破坏的情况下,消除主属性对候选键的依赖,所以可以得出分解后为{abcde}→{acd,bcde}→{acd,ced,bce}。
个人认为,这对于我以后将要进行的项目实践,非常有意义。
推荐阅读
-
C#基于SQLiteHelper类似SqlHelper类实现存取Sqlite数据库的方法
-
PHP数据库操作之基于Mysqli的数据库操作类库
-
php基于session实现数据库交互的类实例
-
基于Docker的PHP调用基于Docker的Mysql数据库
-
PHP封装mysqli基于面向对象的mysql数据库操作类与用法示例
-
基于B-树和B+树的使用:数据搜索和数据库索引的详细介绍
-
PHP封装的数据库模型Model类完整示例【基于PDO】
-
基于Enterprise Library的Winform开发框架实现支持国产达梦数据库的扩展操作
-
基于Python的SQL Server数据库实现对象同步轻量级
-
C#基于SQLiteHelper类似SqlHelper类实现存取Sqlite数据库的方法