什么是Hi / Lo算法?
我在NHibernate文档中找到了这个(这是生成唯一键的一种方法,第5.1.4.2节),但我没有找到它如何工作的很好的解释。
我知道Nhibernate处理它,我不需要知道内部,但我只是好奇。
答案 0 :(得分:507)
基本思想是你有两个数字来组成一个主键 - 一个“高”数字和一个“低”数字。客户端基本上可以增加“高”序列,因为它知道它可以安全地从前一个“高”值的整个范围生成密钥,具有各种“低”值。
例如,假设您有一个当前值为35的“高”序列,而“低”号则在0-1023范围内。然后客户端可以将序列递增到36(对于其他客户端,当它使用35时能够生成密钥)并且知道密钥35 / 0,35 / 1,35 / 2,35 / 3 ... 35/1023是全部可用。
能够在客户端设置主键非常有用(特别是使用ORM),而不是在没有主键的情况下插入值,然后将它们提取回客户端。除了其他任何东西,它意味着您可以轻松地建立父/子关系,并在执行任何插入之前将所有键都放在适当的位置,这样可以简化它们的批处理。
答案 1 :(得分:147)
除了Jon的回答:
它用于能够断开连接。然后,客户端可以向服务器请求hi数字并创建增加lo数量的对象。在lo范围用完之前,它不需要联系服务器。
答案 2 :(得分:24)
hi / lo算法将序列域分成“hi”组。同步分配“hi”值。每个“hi”组都被赋予最大数量的“lo”条目,可以通过离线分配而不必担心并发重复条目。
标识符范围由以下公式给出:
[(hi -1) * incrementSize) + 1, (hi * incrementSize) + 1)
和“lo”值将在以下范围内:
[0, incrementSize)
从起始值:
开始应用[(hi -1) * incrementSize) + 1)
当使用所有“lo”值时,将获取一个新的“hi”值并继续循环
您可以在this article中找到更详细的说明:
这种视觉呈现也很容易理解:
虽然hi / lo优化器适用于优化标识符生成,但它不能很好地与其他系统在我们的数据库中插入行,而不了解我们的标识符策略。
Hibernate提供pooled-lo优化器,它将hi / lo生成器策略与互操作性序列分配机制相结合。该优化器既高效又可与其他系统互操作,是比以前的传统hi / lo标识符策略更好的候选者。
答案 3 :(得分:20)
Lo是一个缓存的分配器,它将键空间分成大块,通常基于某些机器字大小,而不是人类可能合理选择的有意义大小的范围(例如,一次获得200个键)。
Hi-Lo的使用往往会在服务器重启时浪费大量的密钥,并产生大量的人类不友好的密钥值。
比Hi-Lo分配器更好,是“线性块”分配器。这使用了类似的基于表格的原则,但是分配了小的,方便大小的块和&产生良好的人性化价值观。
create table KEY_ALLOC (
SEQ varchar(32) not null,
NEXT bigint not null,
primary key (SEQ)
);
分配下一个,比方说200个密钥(然后在服务器中保存为一个范围并根据需要使用):
select NEXT from KEY_ALLOC where SEQ=?;
update KEY_ALLOC set NEXT=(old value+200) where SEQ=? and NEXT=(old value);
假设您可以提交此事务(使用重试来处理争用),您已经分配了200个密钥&可以根据需要分发它们。
如果块大小只有20,这个方案比从Oracle序列分配快10倍,并且在所有数据库中都是100%可移植的。分配性能相当于hi-lo。
与Ambler的想法不同,它将键空间视为连续的线性数字线。
这避免了复合键的推动(这从来就不是一个好主意),并避免在服务器重启时浪费整个lo-words。它生成“友好”的人类关键值。
相比之下,Ambler先生的想法是分配高16位或32位,并在hi-words增量时产生大的人类不友好的键值。分配密钥的比较:
Linear_Chunk Hi_Lo
100 65536
101 65537
102 65538
.. server restart
120 131072
121 131073
122 131073
.. server restart
140 196608
在设计方面,他的解决方案在数字线(复合键,大型hi_word产品)上基本上比Linear_Chunk更复杂,同时没有实现相对的好处。
Hi-Lo设计在OO映射和持久性早期出现。目前,Hibernate等持久性框架提供了更简单,更好的分配器作为默认设置。
答案 4 :(得分:1)
根据我的经验,我发现Hi / Lo算法非常适合具有复制方案的多个数据库。想象一下。你有一个服务器在纽约(别名01)和另一台服务器在洛杉矶(别名02)然后你有一个PERSON表...... 所以在纽约,当一个人被创造时...你总是使用01作为HI值而LO值是下一个secuential。例子。
在洛杉矶你总是使用HI 02.例如:
因此,当您使用数据库复制(无论什么品牌)时,所有主键和数据都可以轻松自然地组合,而无需担心重复的主键,冲突等。
这是此方案中的最佳方式。