序列不在 oracle 表上的一行中
Posted
技术标签:
【中文标题】序列不在 oracle 表上的一行中【英文标题】:sequence is not in a row on oracle tables 【发布时间】:2021-12-05 10:09:45 【问题描述】:我有一个项目,它的结构是java ee 7。我使用hibernate作为ORM,我的数据库是Oracle。
我使用 @SequenceGenerator
和 allocationSize = 1 作为我的实体的 id 和 @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
。我在 Oracle 中的数据库序列缓存 = 1000。
但是当我在数据库中持久化两条记录时,第一条记录的 id 比第二条记录早,即使在一天之后,id 不是连续的。
我该如何解决这个问题,我的问题是什么?
【问题讨论】:
您在使用 Oracle RAC 吗? 您使用的是哪个版本的 Oracle?从 12.1 开始,您可以使用identity columns
,然后您不需要自己创建任何手动序列。
@pmdba 是的,我正在使用 Oracle RAC。
@RobertoHernandez 我的 oracle 版本是 11G。oracle 11 有解决方案吗?
【参考方案1】:
如果您在每个节点上都有无序(单独)缓存(默认):
node 1: cache values (1 - 1000)
node 2: cache values (1001 - 2000)
那么缓存不能重叠值并且使用的值将取决于哪个节点执行插入。这就是为什么您的序列值目前看起来乱序的原因。
使用NOCACHE
和/或ORDERED
选项将产生序列号,但您可以预期至少会对您的应用程序产生一些性能影响,因为数据库必须执行更多开销才能确定当前序列值,然后才能使其可用到您的 SQL 命令。如果您正在执行大量插入操作(正如您当前的缓存值 1000 所建议的那样),减小缓存大小或完全消除缓存可能会对性能产生严重的负面影响。
假设您现在继续使用缓存(无论是否有序),请注意每次重新启动数据库或节点(取决于您的确切配置)时,未使用的缓存值将被刷新并丢失并且将创建一个新的缓存。
最后,重要的是要意识到序列值(对于大多数应用程序)不是完全连续的,没有间隙,甚至(如您的情况)是有序的。它们仅旨在唯一。请务必了解您的要求,如果序列的行为与您预期的不太一样,请不要推迟:值必须按照插入的顺序是连续的,并且序列中的间隙会影响您的应用?如果答案是否,应用程序不会在意,那么为了性能,坚持使用现有的。
【讨论】:
【参考方案2】:由于您使用的是 11g(一个非常旧的版本,因此您的公司应该尽快考虑升级),因此必须通过 RAC 选项以在性能和完整性差距之间取得平衡。
noorder
和 order
有两种选择
create sequence xxx start with 1 increment by 1 noorder|order cache xxx
实例如何协调它们对序列值的使用并避免两个实例使用相同值的风险?
有两种解决方案:默认的noorder
机制,其中每个实例的行为就像它不知道其他实例一样。另一个是order
选项,实例通过使用全局入队不断协商,以确定哪个实例应随时负责该序列。
无序
这种无序机制的结果是每个实例将通过不同的数字范围工作,并且实例之间不会有重叠。如果您有会话每秒登录一次数据库以发出对 nextval 的调用(并且它们最终每次都通过不同的实例进行连接),那么返回的值似乎相当随机地分散在由“实例数 x 缓存大小。”唯一性会得到保证,但排序不会。
订购
如果您使用order
选项声明一个序列,Oracle 会采用一种策略,即对值使用单个“缓存”,并引入一种机制来确保一次只有一个实例可以访问和修改该缓存。 Oracle 通过利用其 Global Enqueue 服务来做到这一点。每当会话发出对nextval
的调用时,该实例都会在序列缓存上获取一个排他性 SV 锁(全局入队),有效地表示“谁拥有关于这个序列的最新信息——我想要控制”。在独占模式下持有 SV 锁的一个实例是唯一可以增加缓存值的实例,如果需要,可以通过增加高水位来更新 seq$ 表。这意味着序列号将再次按顺序生成。但此选项会降低性能,应慎重考虑。
总结
如果您的交易速度很快,您可以使用 order 并测试它的行为方式。如果您的交易不快,我会一起避免order
。最好的选择是升级到 19c(12c 已经接近淘汰)并使用IDENTTTY COLUMNS
【讨论】:
以上是关于序列不在 oracle 表上的一行中的主要内容,如果未能解决你的问题,请参考以下文章