【问题标题】:Explanation of NHibernate HiLoNHibernate HiLo的解释
【发布时间】:2010-04-29 15:41:08
【问题描述】:

我正在努力弄清楚 HiLo 生成器在 NHibernate 中的工作原理。我已经阅读了here 的解释,这让事情变得更清楚了。

我的理解是每个 SessionFactory 从数据库中检索高值。这提高了性能,因为我们无需访问数据库即可访问 ID。

上述链接的解释还指出:

例如,假设您有一个当前值为 35 的“高”序列,而“低”数在 0-1023 范围内。然后客户端可以将序列增加到 36(以便其他客户端能够在使用 35 时生成密钥)并知道密钥 35/0、35/1、35/2、35/3... 35/1023 是全部可用。

这在 Web 应用程序中是如何工作的,因为我不是只有一个 SessionFactory,因此只有一个 hi 值。这是否意味着在断开连接的应用程序中,您的实体表中可能会出现重复(低)ID?

在我的测试中,我使用了这些设置:

<id name="Id" unsaved-value="0">
  <generator class="hilo"/>
</id>

我进行了一项测试以保存 100 个对象。我表中的 ID 从 32768 到 32868。下一个 hi 值增加到 2。然后我再次运行测试,ID 在 65536 - 65636 范围内。

首先,为什么从 32768 而不是 1 开始,其次为什么从 32868 跳到 65536?

现在我知道我的代理键不应该有任何意义,但我们确实在我们的应用程序中使用它们。为什么我不能像 SQL Server 标识字段那样让它们很好地递增。

最后谁能给我解释一下 max_lo 参数是如何工作的?这是可以针对高值创建的低值(我脑海中的实体 ID)的最大数量吗?

这是 NHibernate 中的一个主题,我一直在努力寻找文档。我阅读了整本 NHibernate in action book,但仍然没有详细介绍它的工作原理。

谢谢 本

【问题讨论】:

    标签: .net nhibernate


    【解决方案1】:

    我相信你的理解或多或少是正确的。 max_lo 参数仅用于确定可用于任何给定 Hi 值的 Id 数量。

    我最好的猜测是 NHibernate 的默认 max_lo 值是 32768。因此,Hi 值 1 将在 32768 开始您的 Id 并运行到 65535。Hi 值 2 将从 65536 开始并运行另一个 max_lo Ids .

    基本上你使用 max_lo 值来控制 Id 碎片。 32768 可能不是每种情况的最佳值。

    需要注意的是,这仅在 SessionFactory 范围内有效。如果您正在停止/启动您的应用程序并重新初始化 SessionFactory 一大堆,无论如何它都会在启动时增加 Hi 值,并且您会看到您的 Id 快速跳跃。

    【讨论】:

    • 默认的 max_lo 值为 java short.MAX_VALUE==2^15-1=32767
    【解决方案2】:

    查看我的 Nhibernate 3 HiLo 对象生成的密钥,算法如下所示: (Hi * Lo) + Hi

    所以我在 DB 中的 Hivalue 为 390,我的配置如下:

    <id name="TimeclockId" column="TimeclockId" type="Int64" unsaved-value="0">
          <generator class="hilo">
            <param name="where">TableId = 1</param>
            <param name="table">HiValue</param>
            <param name="column">NextValue</param>
            <param name="max_lo">10</param>
          </generator>
        </id>
    

    我重新启动我的应用程序池并得到 (390 * 10) + 390 = 4290,范围是 4290 - 4300。

    这就是为什么您的主键中出现看似奇怪的间隙的原因,因为从 hi 值 391 生成的下一个键是 4301,范围是 4301 - 4311。

    【讨论】:

    • 这是一个很好而且干净的解释。尽管他们实际上将公式塑造为 (max_lo + 1) * hi 。我认为它更清晰,并指出您的 id 域被分成与 max_lo+1 值一样大的部分,而不是 max_lo 。
    【解决方案3】:

    对于那些想知道如何选择一个好的max_lo 值的人来说,权衡取舍基本上是:

    • 您需要从数据库中查询新的hi 值的频率。
    • 您实际可以生成的唯一编号的最大数量。

    较低的max_lo 将确保没有“浪费” id,这反过来又控制了您将达到数据类型的隐式限制的时刻(可能是int)。你付出的代价是每个客户端都需要更频繁地查询和增加hi的值。

    较高的max_lo 有助于减少获取和增加hi 的查询频率,但会导致更多浪费。

    确定最佳值需要考虑的指标是:

    • 创建新实体并需要 ID 的频率
    • 应用程序重新启动/被回收的频率(任何会导致新的 NHibernate SessionFactory)

    让我们考虑一个托管在 IIS 中并每 24 小时回收一次的 Web 应用程序。实体是CustomerOrder

    现在假设:

    • 每 24 小时 10000 个新订单
    • 每 24 小时 10 个新客户

    那么完美的max_lo 是用于订单的10000 和用于客户的10。当然,在现实世界中,你永远无法如此准确和清晰地确定它,但你应该在这里得到这个想法!

    现在让我们考虑不同的场景,我们选择完全错误(荒谬)max_lo's:

    • 假设每秒有 10 位客户同时下订单,max_lo 只有 10 个订单,每秒有一个多余的数据库调用来增加 hi
    • 假设您的应用程序是桌面应用程序并安装在 50 个客户端(支持人员?)上,每个客户端大约每天启动两次。他们每天一起创建大约 100 个帮助台工单。现在假设我们坚持使用 max_lo 默认值 32767。Hi 每天递增 100 次(50 个客户 * 2),这意味着您将在不到 2 年的时间内达到 int 的最大值,您是否忘记了hi 如此频繁地递增的重要事实。一个好的max_lo 应该是(100 张票 / 50 个客户)= 只有 2 个。

    希望这有助于概念化 HiLo 算法及其总体含义,同时也为您提供数学以在 max_lo 上实际粘贴一个数字。

    【讨论】:

      【解决方案4】:

      NHibernate 3.1.1 这样做是为了使用 HiLo 生成 ID

      if (lo > maxLo)
      {
          long hival = <GetNextHiFromDB>
          lo = hival == 0 ? 1 : 0;
          hi = hival * (this.maxLo + 1L);
      }
      long result = hi + lo;
      lo++;
      return result;
      

      在 NHibernate 配置中,您指定 maxLo。如果 maxLo 设置为 100,则每个 hi 值将获得 101 个 id。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-16
        • 1970-01-01
        • 1970-01-01
        • 2021-10-16
        相关资源
        最近更新 更多