今天在学习Hibernate,在看到复合主键的时候,笔者有以下论述。
“从设计角度而言,我们推荐对于每个表都定义一个与业务逻辑无关的id字段用作库表记录的唯一识别,而尽量不要将业务逻辑牵扯到数据逻辑中去,数据逻辑和业务逻辑位于两个不同的层面,这一点在设计中应有其清晰的边界划定。否则业务逻辑的变化将直接对底层数据逻辑产生根本性影响。”
当看到上面所述思想时,我困惑了。因为它和我接受的数据库设计出入蛮大的,从大学学习数据库设计到目前公司用的产品的数据库设计均Base在业务逻辑上的。当然也就用到了很多很多复合主键。如果只定义一个无意义的主键,那业务逻辑的控制怎么办?会不会存在很多数据冗余?由程序里面来控制会不会程序逻辑考虑的不周全,造成错误资料保存到数据库?带着些许疑惑,我在网上查阅了部分资料。对所谓的业务主键和逻辑组件也有了进一步的认识。以下为在网上找的相关资料。
资料一、
昨天令狐因为处理动网论坛的数据库时,发现它是用帖子号来作为主键,由于无意中对它作了一些修改,导致帖子的关联变得混乱了。于是我们讨论了一下数据库表中主键的选择问题。因为对动网论坛的程序不熟,所以我也不知道它是怎么设计实现的,今天令狐把JavaEye上的一个关于这个方面的话题拿来讨论就好办了。我起初也觉得用一个无意义的逻辑主键是一个好办法,至少说用一个字段就可以唯确定一条记录,使用上会很方便,速度应该也会快些。但是看了JavaEye那个帖里的讨论,以及在QQ.群里的讨论后,我发现不完全是这样的。其实这是两种不同的设计思路,谈不上用逻辑主键一定比用业务主键好。用业务主键是传统的C/S应用开发的思路,包括我现在用的SAP里,也大量使用业务主键。 但如果用O/R Mapping,则可能用逻辑主键好一些。 因为对于传统C/S应用来说,以典型的两层结构看,前端处理的是一个数据表示的工作,后端处理的是一个数据持久化的工作。业务逻辑分散在两端,特别是在后端。因为需要在后端通过Stored Procedure和View等来实现业务逻辑,应用直接与关系数据库打交道,所以数据的记录不但要求便于程序访问,对开发者来说,还要易读。也就是说需要数据库的关系逻辑能够清晰地表达出业务逻辑来。主键采用业务主键是自然甚至是必须的。而ORM应用恰恰相反。它需要一个最简单的 办法来标记一条唯一记录,但不需要有具体的意义,就像在OOP中,我们访问一个Object总是通过指针(或相似的引用),但我们并不需要知道这个指针具体的值是0x89ABCDEF还是0xFEDCBA98。逻辑主键就相当于一个指针,当别的关联表引用到这条记录时,用一个外键字段记录了这个逻辑主键,就相当于那个Object中有一个属性记录了一个指向这个Object的指针。这时如果用业务主键--特别是复合业务主键--就是存心给自己打麻烦了。最糟糕的情况就是当需要修改这个业务主键的值的时候,会导致所有的关联发生混乱--在传统C/S应用中,我们是用Trigger来解决这个 问题,但是在ORM中不可能这样做,否则那还要ORM干什么? 当然,对于开发者来说,在ORM这样的情况下,用逻辑主键存在一个至关重要的问题就在于数据的可读性将要变差。也就是说,除非通过OO的视角来看数据才是易于理解的。但如果直
接进入后端看关系数据库,将变得困难。因此,基本上,逻辑主键与ORM是相辅相成的,
缺一不可,并且采用ORM的开发者要尽可能避免与后端的关系数据打交道,否则就会非常的痛苦。
资料二、 关于这个问题网上已经有很多的讨论,现在综合这些讨论在加上自己众多建模及数据仓库工作中的经验
给出以下分析及取舍建议,供各位同行参考:
一、业务的东西,是每一个做软件的最薄弱的,并且是最有可能受到客户影响的,
也是最会引起问题的。 比如身份证,如果有系统的表用此做主键,其他众多表以此为外键,当身份证从15位升到18位时,整个数系统的重构将是一个非常困难的工作。一个系统在维护的成本远大于开发的成本,所以要 充分考虑客户业务变更的需求,用户今天说不会变,而明天可能就变了,即使用户已经对需求 确认签字。这些都是不可预知的。
二、业务主键在存在主从关系时候,更新时不方便(这样你必须要检查从表,再处理主表)。
三、业务主键是复合型时,CRUD操作时不方便(比如要定位一条记录时必须传入复合的每个字段,
四、使用业务主键,基于源数据的质量问题,往往存在业务主键重复,对于源数据可控及数据量小的 操作,业务主键重复还容易控制,而对于某些高度耦合的系统来说, 后果是不堪设想的。
五、数据仓库的表中的冗余字段不是很少而是大量的,增加逻辑主键并不是冗余的根源。建议设计的基本原则(具体情况可能要具体分析):
一、对于业务数据,最好采用逻辑主键;
二、对于业务复合主键有多个字段(>3?),需要采用逻辑主键;
三、对于基础数据,基于多方面考虑,是可以采用业务主键的。这类表初始化以后数据不会经常发 生改变。
四、取消业务主键后,在查询经常会用到的相关的业务字段建立INDEX,可以提高查询效率;
五、使用逻辑主键,表的业务数据唯一性由程序来检查控制,使业务数据重复这类脏数据控制在业务允许的范围;
六、业务数据的重复这类脏数据也可以通过分析结果数据得到;
七、业务数据的逻辑主键使用numeric自增长型,在迁移数据时,取消目标表的自增长, 数据迁移完成后,再重建逻辑主键。
看了上面两段资料和网上的一些评论。自己现在也比较偏向逻辑主键的建立了。也打算在以后的数据库设计中打算尝试去使用。如果有看到的朋友对这方面有什么体会,不妨回复,供大家讨论讨论。