征求意见:所有表格的一个序列

Posted

技术标签:

【中文标题】征求意见:所有表格的一个序列【英文标题】:Asking for opinions : One sequence for all tables 【发布时间】:2010-12-04 22:07:31 【问题描述】:

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

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

【问题讨论】:

“我们已经在之前的讨论中得出结论”——内部讨论还是关于 SO 的? 关于 SO 的几次讨论。而“我们”的意思是“我”;-) 自然键并不“坏”。从数据完整性的角度来看,它们是必不可少的。它们允许用户识别数据库中正在识别的真实世界事物。原则上,序列也可以是自然键。实际上,我更喜欢“业务密钥”一词,但它与“自然密钥”的含义相同 - 即用于识别数据库外部信息的密钥(例如由业务用户)。 @dportas - 自然键很有用,尽管在应用程序中使用自然键作为主键/@@Id 字段可能很糟糕,当您的应用程序是这些值的记录系统时这些值可能需要稍后更改。多年前,当我将 username 设置为 @@Id 列时,我很难学到这一点(好吧,当时没有注释)。这是一个清晰的自然键——具有商业意义的唯一记录标识符。唯一的问题是,如果您需要更改它并且有 10 个其他表使用它作为外键怎么办? 【参考方案1】:

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

【讨论】:

在我们的例子中,当我们显着增加序列的缓存时,单序列和多序列的性能是相似的。 啊,您可能还想向下滚动该线程并查看 Mark Bobaks 先生的回复,这反映了我的经历 @Edwards 感谢您指出这一点,确实非常有趣。 “Oracle 序列的最大值实际上是 10^27”——理论上你可以创建几个序列并适当地错开起始值。请务必设置一个脚本,以便在您的应用运行非常非常长的时间时通知管理员。【参考方案2】:

取决于序列在数据库中的实现方式,总是命中相同的序列可能更好或更糟。当只有少数或只有一个线程请求新值时,不会出现锁定问题。但糟糕的实现可能会导致拥塞。

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

最后,如果需要的话,你不能轻易地重置序列。但是,如果您需要重新启动序列(例如,从午夜开始的记录数),您可以告诉 Hibernate 创建/使用第二个序列。

一个主要优点是您可以仅通过 ID 唯一地标识数据库中任何位置的对象。这意味着你可以严重削减你在生产系统中写入的日志信息,如果你只有 ID,仍然可以找到一些东西。

【讨论】:

Ref: "2 或 40 亿个 ID(如果使用 32 位(有符号)整数)",Oracle 序列的最大值实际上是 10^27,Oracle NUMBER 类型将存储整数高达 38 位精度。应该让我们坚持一段时间。 我的意思是“即使你只使用 32 位整数”作为 ID。今天的大多数人将使用 64 位(LONG 或 BIGNUM)或更多甚至 UUID。 确实如此。我的评论实际上是要指出 Oracle 数字数据类型与其他系统有很大不同。此处参考文档:download.oracle.com/docs/cd/B19306_01/server.102/b14200/… 如果您使用 NUMBER,数字用完应该不是问题。以每秒一万亿笔交易的速度运行,您可以使用 3160 万年。【参考方案3】:

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

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

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

select * from orders where customerid=415

select * from orders where customerid=89461836571

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

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

【讨论】:

【参考方案4】:

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

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

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

【讨论】:

【参考方案5】:

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

您可以仅通过 ID 唯一标识数据库中任何位置的对象

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

此外,最新版本 (1.2) 的 Grails 不支持此序列映射。尽管 Grails 1.1 (!) 支持它。它现在需要子类化 Hibernate 方言类之一作为解决方法。

对于使用 Grails/GORM 的用户,请查看以下 JIRA 条目:

Oracle Sequence mappings ignored

【讨论】:

解决方法(和 Java 代码)总结在这里 --> ***.com/questions/2564491/…

以上是关于征求意见:所有表格的一个序列的主要内容,如果未能解决你的问题,请参考以下文章

《互联网信息服务管理办法》征求意见:违规拟计入信用档案

《互联网信息服务管理办法》征求意见:违规拟计入信用档案

通知!三项预制装配整体式模块化建筑标准开始征求意见了!

文件 | 《四川省新一代人工智能发展实施方案(2018-2022)》(征求意见稿)

《5G应用“扬帆”行动计划(2021-2023年)》征求意见稿发布

工信部数据安全标准征求意见稿:重点在区块链等领域进行布局