论坛首页 Java企业应用论坛

数据库设计讨论,是否应该将所有的数据逻辑关系都建立FK

浏览 12253 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2004-10-22  
一张表被几十张表引用并不可怕,可怕的是,表与表之间的关系引用成了一张复杂而零乱的图结构的时候,问题就来了。
   呵呵,其实最简单的方法,就是将数据库的表结构用PowerDesigner生成数据模型图,看看图,当大家都能看懂的时候,证明它还好,如果没有几个人搞得清楚他们之间的关系结构的时候,那就是数据库设计的最大败笔。
   readonly用程序来表现数据库结构的设计并不合适,盲目地套用3NF来进行数据库设计也不合适。在数据库设计中,冗余是根据需要而必须的。简单地举些例子,我曾做过基于订单的MRP系统,百多张表是肯定有的,可以讲,在整个系统中都无数过引用到了订单表,并且相互之间形成多层次的关系。但我相信没有任何一个人会纯粹靠关系外键来维护和构造这些物理层次间的关系,否则,根本就没有办法做下去。另外,做过财务系统的可以看一看现有的财务软件的数据库设计(因为我做审计软件,所以接触过一些),在许多人眼中保准就是极其低劣,呵呵,不过真要换成他们来做,也不会好到哪里去。
   简洁清晰的关系结构,合理的结构描述,良好的性能是数据库结构设计都需要考虑的关键,盲目追求一种某一项,只会是给其他带来灾难。
0 请登录后投票
   发表时间:2004-10-22  
robbin 写道
前一个例子,你可以把你说的那20多个表关联到person一个表上以及这些数据代表的业务含义描述出来,我们再讨论是否有拆分的可能,毕竟你现在举的3个对象关联并不能够证明你的命题。

后一个例子按照你的做法,那就是凡是涉及到单位换算的对象,统统有一个getUom()方法,对于数据库表来说,这些涉及到单位换算的对象,统统要FK到uom表。但是按照当前的这种情况,单位换算对于这些实体对象来说,不是一个偶合很紧要的东西,我就是对象没有这个getUom(),也就是我不建立FK,我也一样可以写代码额外检查。并且这些检查代码的代价是很低的。你觉得把几百个表都建立FK关联到uom上面,所有的实体对象都附加一个getUom()方法上,所有的实体读去都要关联查询的代价高呢,还是在代码里面写一点点额外检查的代价高呢?


yuzs2000的观点是: 为了灵活应用, 2个表发生关联的话, 外键是不一定要建立的.
Robbin的观点是: 如果外键关联很多的话(超过20个?), 就是一个糟糕的设计.
偶的观点是: 为了保证数据的严谨,一致, 2个表发生关联的话, 外键是一定要建立的, 而且外键多更本不是用来批判设计的理由.

对于yuzs2000的观点偶就不重复yyanghhong的话了......

对于Robbin的观点
1. 拆分的可能
回到偶前面举的HR系统, Contract 是员工合同对象, getPlanPeriod() 是合同的计划开始/结束时间,  getActualPeriod()是合同的实际开始/结束时间.
PayrollDetail 是工资条目对象, getPayPeriod() 是代表公司为该员工支付薪资的时间段, getAmout()当然就是$的数目了.
再多举一个培训模块里的, 培训记录:
public interface TrainingRecord {
    public Person getPerson();;
    public Period getTrainingPeriod();;
    public String getCourseName();;
    public Address getAddress();;
}

再加上偶前面说的人员与组织, 个人升降职, 个人联系方式......等等模块, 偶们怎么来拆分, 而不让他们与Person这个对象发生关联么(要知道这些模块管理的就是Person哦)

2. 性能问题:
还是一句老话, 关联查询带来的效率损失, 随便什么地方加一个小小的Cache, 减少一次数据查询, 带来系统性能的整体提高和它相比都是数量级的差别. Cache is the king.

另外, 偶什么时候说过建立了FK, 就必须要用关联查询去查询么? 在没有Hibernate/JDO这些先进武器的时候, 偶的土制O/R代码是这样的 (一个代表供水管道的材料, Uom在这里是一个长度单位):

public class CityWaterLine implements NormalLine {
    public Uom getUom();{
        uomManager.loadUom(umoId);;
    }
}    

偶们可以在UomManager里面做Cache, 性能损失? 偶不知道损失在哪里?
0 请登录后投票
   发表时间:2004-10-24  
外键是一种数据库层约束,是一种错误检测的手段。
一般来说,外键不会影响查询的效率。因为查询的时候,是不需要改变数据库的值,所以这个地方不会影响查询的效率。至于更新,我以为,只要数据是人敲进去的,就不用考虑更新效率。想用人工录入数据去搞死一台P4的机器,几百号人怕是不够的。
3NF是最基本的数据库范式。除了极少数对于查询效率要求极高的场合,一般都是应该遵守的。有些查询为了减少关联的层数,是有反规范化的需要,但是这个与是否使用外键没有关系。像这种对查询效率要求很高的场合,一般都允许延时,可以用别的方法来处理。
如果不是以上的情况,除了便于输入错误的数据,实在想不出其他理由来不使用外键了.
0 请登录后投票
   发表时间:2004-10-24  
马丁叔叔的refactoring系列中也有数据库refactoring的文章:

http://www.martinfowler.com/dbrefact/index.html

其中有一篇就是讲加上外键约束的:

http://www.martinfowler.com/dbrefact/AddForeignKeyConstraint.html


mooniscrazy 写道

如果不是以上的情况,除了便于输入错误的数据,实在想不出其他理由来不使用外键了.

, 不过偶们的DBA曾经抱怨过, 由于外键约束的存在不能很方便地独立备份/恢复数据库中部分表, 被偶洗脑多次以后就闭嘴了......
0 请登录后投票
   发表时间:2004-10-24  
Readonly 写道

, 不过偶们的DBA曾经抱怨过, 由于外键约束的存在不能很方便地独立备份/恢复数据库中部分表, 被偶洗脑多次以后就闭嘴了......


oracle里export或import都有选项处理FK或trigger, 多写两句就可以了,

如果备份/恢复数据库象xcopy一样简单, 还要DBA干嘛
0 请登录后投票
   发表时间:2004-10-24  
robbin 写道


你用不着拿几十个表吓我。我开发过150个表以上的制造行业软件系统。不管表多还是少,不管软件系统之间的逻辑关系有多复杂,一个最基本的设计原则就是“简化”,把复杂的问题分解,用清晰的逻辑关系去表达。这个基本原则不管你是对象建模还是数据建模都是一样的。而你那种几十个表都关联到一个表上的做法,不管你哪种设计思路出发,都是terrible的!

这种关联,我认为是一种必要的约束。代码中需要约束,数据库中也需要约束。约束能增强程序的健壮性。我在数据库里面约束了,在代码中再约束,也没有什么不好。诸葛一生唯谨慎。我连自己的代码都是不信任的,何况别人写的代码。多一次约束,我晚上睡觉就可以安稳一点。
确实,关联多了,倒数据会不方便,我就是要他们不方便,不方便那些DBA把错误的数据倒进数据库。
随意往数据库添加数据,本来就是危险的行为。这样就更有必要使用更多的数据库约束了。
DBA有时候是项目的敌人,不能为了他们方便而放弃项目自卫的手段。
0 请登录后投票
   发表时间:2004-10-24  
robbin 写道
前一个例子,你可以把你说的那20多个表关联到person一个表上以及这些数据代表的业务含义描述出来,我们再讨论是否有拆分的可能,毕竟你现在举的3个对象关联并不能够证明你的命题。

后一个例子按照你的做法,那就是凡是涉及到单位换算的对象,统统有一个getUom()方法,对于数据库表来说,这些涉及到单位换算的对象,统统要FK到uom表。但是按照当前的这种情况,单位换算对于这些实体对象来说,不是一个偶合很紧要的东西,我就是对象没有这个getUom(),也就是我不建立FK,我也一样可以写代码额外检查。并且这些检查代码的代价是很低的。你觉得把几百个表都建立FK关联到uom上面,所有的实体对象都附加一个getUom()方法上,所有的实体读去都要关联查询的代价高呢,还是在代码里面写一点点额外检查的代价高呢?

这个,对于一些基本不变的数据,可以用一个实现Singleton的集合,不用去查询的。如果变了,通知这个集合更新就可以了。这个,我们把它叫做固定有限集合。但是,尽管我们在代码里面约束了,数据库仍然用外键约束。我们绝对不给不了解项目的Dba破坏数据完整性的机会。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics