Algorithm 使用HiLo后,如果更改容量(最大Lo),会发生什么情况?

Algorithm 使用HiLo后,如果更改容量(最大Lo),会发生什么情况?,algorithm,hilo,Algorithm,Hilo,如果我开始使用HiLo生成器为表分配ID,然后决定增加或减少容量(即最大“lo”值),这是否会导致与已分配ID的冲突 我只是想知道我是否需要在号码周围挂一个大红旗,上面写着“永远不要改变这个!” 注意-不是特定于NHibernate,我只是对HiLo算法总体上很好奇。根据经验,我会说:是的,减少会导致碰撞。当您有一个较低的max-low时,您会得到较低的数字,与数据库中的高值无关(处理方法相同,例如在NH的情况下,每个会话工厂实例的增量) 有一种可能性是,增加会不会导致碰撞。但是,您需要尝试或询

如果我开始使用HiLo生成器为表分配ID,然后决定增加或减少容量(即最大“lo”值),这是否会导致与已分配ID的冲突

我只是想知道我是否需要在号码周围挂一个大红旗,上面写着“永远不要改变这个!”


注意-不是特定于NHibernate,我只是对HiLo算法总体上很好奇。

根据经验,我会说:是的,减少会导致碰撞。当您有一个较低的max-low时,您会得到较低的数字,与数据库中的高值无关(处理方法相同,例如在NH的情况下,每个会话工厂实例的增量)


有一种可能性是,增加会不会导致碰撞。但是,您需要尝试或询问比我更了解的人来确定。HiLo算法通常基本上将两个整数映射到一个整数ID。它保证每个数据库中的数字对是唯一的。通常,下一步是确保一对唯一的数字映射到一个唯一的整数ID

关于HiLo在概念上是如何工作的,在中给出了一个很好的解释

更改max_lo将保留您的数字对唯一的属性。但是,它会确保映射的ID是唯一的且无冲突的吗

让我们看看Hibernate对HiLo的实现。他们似乎使用的算法(从我收集的数据来看)是:(而且我可能在技术上有问题)

所以,如果你的低块是,比如说,100,你保留的ID块会变成1-100,101-200,201-300,301-400

你的高序列现在是3。如果你突然把你的l_码改成10码会怎么样?你的下一个区块,你的高点会增加,你会得到
4*10+1=41

哎呀。这个新值肯定在
1-100的“保留块”中。高序列为0的人会想,“好吧,我只为我保留了
1-100
的范围,所以我只在
41
上放一个,因为我知道它是安全的。”

降低你的l_max时,肯定有非常非常高的碰撞概率

相反的情况呢,提出它

回到我们的示例,让我们将l_大小提高到500,将下一个键变成
4*500+1=2001
,保留范围2001-2501

在这个特定的HiLo实现中,当提升您的l_max时,似乎可以避免冲突

当然,您应该自己做一些测试,以确保这是实际的实现,或者接近它。一种方法是将l_max设置为100并找到前几个键,然后将其设置为500并找到下一个键。如果像这里提到的那样有一个巨大的跳跃,你可能是安全的

然而,我并不是说在现有数据库上提高l_max是最佳实践

运用你自己的判断力;HiLo算法并不是一个考虑了不同l_max的算法,根据具体的实现,最终的结果可能是不可预测的。也许有人有过提高l_max和发现麻烦的经验,可以证明这个计算是正确的

因此,总之,尽管理论上Hibernate的HiLo实现在l_max被提升时很可能避免冲突,但它可能仍然不是一个好的实践。您应该像l_max不会随时间而改变一样编写代码


但是如果你感到幸运的话…

我试图通过一个简单的HelloWorld-ish hibernate应用程序挖掘HiLo算法的优点

我尝试了一个hibernate示例

<generator class="hilo">
<param name="table">HILO_TABLE</param>
<param name="column">TEST_HILO</param>
<param name="max_lo">40</param>
</generator>
我观察到创建ID的模式是

hivalue * lowvalue + hivalue
hivalue是以DB为单位的列值(即从HILO_表中选择TEST_HILO) lowvalue来自配置xml(40)

所以在本例中,ID从8*40+8=328开始

在我的hibernate示例中,我在一个会话中添加了200行。因此,创建了ID为328到527的行 以DB为单位,hivalue增加到13。 增量逻辑似乎是:-

new hivalue in DB = inital value in DB + (rows_inserted/lowvalue + 1 )
=8+200/40=8+5=13

现在,如果我运行相同的hibernate程序来插入行,ID应该从 13*40+13=533


当运行程序时,它得到了确认。

请参阅线性块表分配器——从逻辑上讲,这是解决同一问题的更简单、更正确的方法

通过从数字空间中分配范围&直接表示下一个
,而不是用高位字或乘法数字使逻辑复杂化,您可以直接看到将生成哪些键

本质上,“线性块分配器”使用加法而不是乘法。如果NEXT是1000&我们已经将范围大小配置为20,那么NEXT将前进到1020,并且我们将保留键1000-1019以进行分配

可随时调整或重新配置量程大小,而不会丢失完整性。分配器的下一个字段、生成的键和表中存在的MAX(ID)之间存在直接关系

(相比之下,“Hi-Lo”使用乘法。如果下一个是50,乘法器是20,那么您分配的键大约在1000-1019之间。下一个、生成的键和表中的MAX(ID)之间没有直接的相关性,很难安全地调整下一个,并且在不干扰当前分配点的情况下无法更改乘法器。)

使用“线性块”,您可以配置每个范围/块的大小——1的大小相当于传统的基于表的“单个分配器”&点击数据库生成每个键,10的大小比它一次分配10个范围快10倍,50或100的大小更快

65536的大小会生成外观难看的密钥,在服务器重启时会浪费大量密钥,这相当于Scott Ambler最初的HI-LO算法

简言之,Hi-Lo是一种错误的、复杂的、有缺陷的方法
hivalue * lowvalue + hivalue
new hivalue in DB = inital value in DB + (rows_inserted/lowvalue + 1 )
SELECT MAX(Id) FROM TableName/(@max_lo + 1) + 1
DECLARE @scripts TABLE(Script VARCHAR(MAX))
DECLARE @max_lo VARCHAR(MAX) = '100';
    
INSERT INTO @scripts
SELECT '
INSERT INTO hibernate_unique_key (next_hi, EntityName)
SELECT
(SELECT ISNULL(Max(Id), 0) FROM ' + name + ')/(' + @max_lo + ' + 1) + 1, ''' + name + ''' 
'
FROM sys.tables WHERE type_desc = 'USER_TABLE' 
AND COL_LENGTH(name, 'Id') IS NOT NULL
AND NOT EXISTS (select next_hi from hibernate_unique_key k where name = k.EntityName)


DECLARE curs CURSOR FOR SELECT * FROM @scripts
DECLARE @script VARCHAR(MAX)

OPEN curs 
FETCH NEXT FROM curs INTO @script

WHILE @@FETCH_STATUS = 0
BEGIN
    --PRINT @script 
    EXEC(@script)
    FETCH NEXT FROM curs INTO @script
END
CLOSE curs
DEALLOCATE curs