询问意见:所有表格的一个序列

时间:2009-10-08 08:43:39

标签: oracle database-design

这是我最近一直在考虑的另一个。 我们在之前的讨论中得出结论:“自然主键是坏的,人工主键是好的。” 之前使用Hibernate我已经看到Hibernate默认为所有表创建一个序列。起初我对此感到困惑,你为什么要这样做。但后来我看到了它使父母和孩子联系起来的优势。由于没有表具有相同的主键值,因此意外地将父项与不是子项的表链接不会产生任何结果。

有没有人看到这种方法的任何缺点。我只看到一个:你的数据库中不能有超过999999999999999999999999999的记录。

5 个答案:

答案 0 :(得分:11)

所有代码从单个序列中获取值可能会出现性能问题 - 请参阅this Ask Tom thread

答案 1 :(得分:7)

根据数据库中序列的实现方式,始终点击相同的序列可能会更好或更差。当只有少数或仅一个线程请求新值时,将不会出现锁定问题。但是糟糕的实施可能会导致拥堵。

另一个问题是回滚事务:序列不会被回滚(因为其他人可能已经请求了更高的值),因此您可能会有很大的间隙,这会比您预期的更快地占用您的数字空间。 OTOH,需要一些时间才能吃掉2到40亿个ID(如果你“只”使用32位(签名)的内容),所以在实践中它很少成为问题。

最后,如果必须,您无法轻松重置序列。但是如果您需要重启序列(例如,自午夜以来的记录数),您可以告诉Hibernate创建/使用第二个序列。

一个主要优点是您可以通过ID唯一地识别数据库中任何位置的对象。这意味着您可以严格删除您在生产系统中编写的日志信息,如果您只拥有该ID,仍然可以找到一些信息。

答案 2 :(得分:5)

我更喜欢每张桌子有一个序列。这来自一个普遍观察:一些表(“主表”)具有相对较小的行数并且必须“永久”保持。例如,ERP中的客户表。

在其他表(“事务表”)中,永久生成许多行,但在一段时间之后,这些行可以存档(或简单地删除)。最极端的例子是用于调试目的的跟踪表;它可能会以每秒数百行的速度增长,但几天后每一行都会过时。

主表中的小ID使得直接在数据库上工作变得更容易,例如:用于调试目的。

select * from orders where customerid=415

VS

select * from orders where customerid=89461836571

但这只是一个小问题。更大的问题是骑自行车。如果对所有表使用一个序列,则根本无法让它重新启动。每个表有一个序列,您可以在归档或删除旧数据时重新启动事务表的序列。主表几乎没有问题,因为它们变得慢得多。

我认为对所有表只有一个序列没什么价值。到目前为止所说的论点并不能说服我。

答案 3 :(得分:2)

使用单个序列有几个缺点: -

  • 降低了并发性。发出下一个序列值涉及同步。在实践中,我不认为这可能是一个大问题
  • Oracle在维护btree索引以检测单调递增值并适当平衡树时有特殊代码
  • 如果大多数值已填写
  • ,CBO可能会更好地估算索引上的范围查询(如果您这样做过)

一个优点可能是您可以确定不同表中插入的顺序。

答案 4 :(得分:1)

当然,单序列与单序列每表的方法有利有弊。就个人而言,我发现能够为行分配一个真正唯一的标识符,使每个id列成为一个uuid,足以获得超过任何缺点的好处。正如Aaron D.简洁地写道:

  

您可以通过ID

唯一地识别数据库中任何位置的对象

而且,对于大多数应用程序,由于Hibernate3批处理IMPORT语句的方式,除非大量记录争夺相同的数据库资源(SELECT hibernate_sequence.nextval FROM dual),否则这不会成为性能瓶颈。

此外,Grails的最新版本(1.2)不支持此序列映射。虽然在Grails 1.1(!)中得到了支持。它现在需要继承Hibernate方言类之一作为变通方法。

对于使用Grails / GORM的人,请查看此JIRA条目:

Oracle Sequence mappings ignored