论坛首页 Java企业应用论坛

为了方便以后在各种数据库间移植,采用那种主键生成方式最好...

浏览 53020 次
该帖已经被评为精华帖
作者 正文
   发表时间:2004-07-27  
使用自己生成主键,比如建张表,一个表名对应一个sequence等,虽然比较经典,比较“跨数据库”,但问题也多多,比如同步竞争锁,比如在集群环境等,
效率也不高。
我们曾经碰到过这些问题,所以,我认为,主键还是用数据库自己的主键机制比较好,或者用uuid,hilo等
0 请登录后投票
   发表时间:2004-08-14  
我个人的人为assigned比较的好
不是什么数据库的主键都可以随便建的
0 请登录后投票
   发表时间:2004-08-14  
关于主键生成方式,主要有以下几种观点:  
  1、使用整数,键值在内存中;
  2、使用整数,将键值保存到数据库中的一个表中; 
  3、使用UUID;

      如果你对性能比较敏感,建议你不要使用UUID,一方面UUID的生成需要花一定的时间,另一方面,UUID的存储占用比整数更多的空间,对性能也很不利;
那么我们应该使用整数作为主键吗,答案是不确定的,要根据实际情况具体分析。
  使用第一种方案,具有最高的效率,象Hibernate中的IncrementGenerator,由于hibernate本身就是跨数据库平台的,所以这种方式不用担心跨数据库平台的问题。但是第一种方案,不能应用在机群环境中。
   第二种方式,能够应用机群环境中,向JBoss中的AutoNumber解决方案就是使用这种方式,但是这种方式也有很大的性能问题,当数据插入密集时,会导致冲突。
   那么有没有一种高效率又能够应用在机群环境中的方案呢?
   第一个方案具有最高的效率,但是不能应用在集群环境中,第二中方案能够应用在机群环境中,但是效率低。那么我们如果将这两种方案结合其来怎么样?那怎么结合呢?
   我们来一起看一下这样的一个方案:我们知道对于第二种方案中,当要生成一个主键值时,系统会去读取并更新一次数据库中的表,相当于一次取值过程,每个主键值的生成都会有至少一次的数据库连接,而这正是性能瓶颈所在。为了解决这个问题,我们在每次“取值“时不是去出一个值,而是一次取出100个或更多,在每次需要生成主键值时,在内存中保存主键值的当前值和取值计数,当这个计数减小到0时,也就是前次取出的主键值已用完,这时再去数据库中取出100或更多的值。通过这种方式大大降低连接数据库的次数,减少冲突的可能性,可以大大提高第二中方案的性能问题,而且可以应用在机群环境中。
    这种方案的取值部分,一般的都部署在一个EJB种,就像JBOSS中的AutoNumber,以进行事务隔离,防止主键更新事务与应用代码混在相同的事务中,当应用代码失败事务会滚时,将主键更新代码也回滚造成主键生成机制混乱。
   当然这种方案也不是没有缺点,应该注意到,每次系统关闭时,都会造成一定的键值空当。大小与每次取值得个数有关。

    在DudoJ框架中就实现了这种主键生成机制。DudoJ还实现了一个主键生成器,它是一个代理类,能够自动在第一种方案和最后一种方案间自动选择,已达到最好的性能。

    欢迎大家对最后一种方案展开讨论。
0 请登录后投票
   发表时间:2004-08-15  
关于这个问题我也想拿出来和大家讨论一下,说得不正确的地方还请大家多多指正的
在我的实际使用的过程中,我只使用assign方式和identity的两种方式,来生成对象的主键,真得不清楚各位所说的效率的问题从何而出。我只知道在数据库的设计中,如果采用uuid方式作为主键的话,造成的后果将使数据记录的无序排列,当两张大表做关联的时候,性能的减低就是惊人的了,当然既然我们做的是设计,那么暂时我们把性能问题抛到一边,暂时不考虑它,我们看看有没有可能在我们的设计中完全照搬uuid的设计的
我的理解uuid是一种强随机主键,依照算法将数据库的记录关联起来,但是问题来了,抛去你的应用系统,你永远不可以检查到你的数据库中是否存在错误地记录,当然错误的产生原因可能是人为的也可能是程序造成的,为什么呢?因为你永远不知道主键的正确内容是什么的?可以这样子来设计数据库的么?我不知道你们设计的系统是在什么环境中使用的,它可以保证数据库记录百分之一百的不会错失么?这个以前如果是业务主键的话是比较好区分的,因为那是自己设计的编码规则,即使做数据库的修复代码也相对容易的,这一点不知道各位是怎么解决这个问题的呢?所以在我的设计系统中如果是相关业务的关联数据表的话,我会采用assigned来生成主键,而如果是独立业务的话,则会采用identity来生成以获得最好的效率的
0 请登录后投票
   发表时间:2004-08-15  
引用
我只知道在数据库的设计中,如果采用uuid方式作为主键的话,造成的后果将使数据记录的无序排列,当两张大表做关联的时候,性能的减低就是惊人的了


怎么叫无序排列?你要按照什么顺序排列?
性能怎么惊人降低了,说说你下这个结论的理论依据或者测试报告。

引用
我的理解uuid是一种强随机主键,依照算法将数据库的记录关联起来,但是问题来了,抛去你的应用系统,你永远不可以检查到你的数据库中是否存在错误地记录


按照算法把记录关联起来?我怎么看不懂这句话,产生UUID的算法怎么和记录之间的关联搞到一起去了?为什么用UUID就无法检查错误的记录了呢?

引用
这个以前如果是业务主键的话是比较好区分的,因为那是自己设计的编码规则,即使做数据库的修复代码也相对容易的


逻辑主键怎么就不好修复呢?

我实在没有领会你的文章要表达的观点
0 请登录后投票
   发表时间:2004-08-15  
引用
UUID的存储占用比整数更多的空间,对性能也很不利


考虑到当前的海量存储硬件,这点空间占用实在算不了什么。至于性能很不利的说法,能不能给个理论依据,或者实际测试报告。我想不出来用char类型做主键,性能损失有如此巨大的任何理由。

我还不太清楚Hibernate是否实现了你在dudo说的那种主键生成策略,不过要在Hibernate中实现这种策略也是易如反掌的事情。

其实我认为在数据库应用中,极其频繁的操作往往都是查询,至于频繁的insert应用实在太罕见,就算有,也不是O/R Mapping适用的场合。所以在主键生成策略上过于追究性能的细节,没有太大的意思。
0 请登录后投票
   发表时间:2004-08-15  
第一第二条一并回答
表述可能有问题,只是我为了说得通俗
我觉得uuid就是数据库设计中的GUID主键
唯一的好处是全球唯一,缺陷是GUID值太复杂.不易记忆,影响数据库效率.GUID的产生不是以一定的次序产生,如果在记录的前部插入一条记录,可能会导致后面N次方的数据条数后移.这将导致数据插入效率,特别是在海量数据存储的过程中这一点,非常的明显,所以我不赞成使用
第三点,在数据库的纠错过程中,人是占主导因素的,你可以指望谁记住uuid这么老长的数字,编码方式则不同,非常容易记忆的,当然我知道这一点在数据设计的过程中是站不住脚的,主键不应该是有意义的字符,可是局在使用过程中是可以简化设计的
0 请登录后投票
   发表时间:2004-08-15  
关于关联,漏答了一点的,就是在父亲加儿子的时候,这一问题尤为明显的,具体的测试报告我没有,这点还请原谅的
0 请登录后投票
   发表时间:2004-08-15  
引用
如果在记录的前部插入一条记录,可能会导致后面N次方的数据条数后移.这将导致数据插入效率,特别是在海量数据存储的过程中这一点,非常的明显


数据条数后移?我还是不懂这句话的意思。是什么东西在移动?难道是数据库记录在文件的物理位置移动了?我为什么插入1条记录,数据库会去移动那么多条记录呢?你肯定数据库会这么做吗?


引用

在数据库的纠错过程中,人是占主导因素的,你可以指望谁记住uuid这么老长的数字,编码方式则不同,非常容易记忆的


你觉得海量数据的纠错是要靠人一条条记录的去记忆的吗?
0 请登录后投票
   发表时间:2004-08-15  
willmac 写道
关于关联,漏答了一点的,就是在父亲加儿子的时候,这一问题尤为明显的,具体的测试报告我没有,这点还请原谅的


什么问题那么明显,你的意思是指用了UUID做主键以后,插入子表的执行效率明显降低,降低到人的知觉都可以测量出来的地步?那我怎么从来没有感觉到呢?
0 请登录后投票
论坛首页 Java企业应用版

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