1

以下代码可以在 NHibernate.Id.GuidCombGenerator 类中找到。该算法基于将“随机”guid 与 DateTime 组合来创建顺序(梳状)guid。我有几个与下面用 *1) 和 *2) 标记的行相关的问题:

private Guid GenerateComb()
{
    byte[] guidArray = Guid.NewGuid().ToByteArray();

    // *1)
    DateTime baseDate = new DateTime(1900, 1, 1);
    DateTime now = DateTime.Now;

    // Get the days and milliseconds which will be used to build the byte string 
    TimeSpan days = new TimeSpan(now.Ticks - baseDate.Ticks);
    TimeSpan msecs = now.TimeOfDay;

    // *2)
    // Convert to a byte array 
    // Note that SQL Server is accurate to 1/300th of a millisecond so we divide by 3.333333 
    byte[] daysArray = BitConverter.GetBytes(days.Days);
    byte[] msecsArray = BitConverter.GetBytes((long) (msecs.TotalMilliseconds / 3.333333));

    // Reverse the bytes to match SQL Servers ordering 
    Array.Reverse(daysArray);
    Array.Reverse(msecsArray);

    // Copy the bytes into the guid 
    Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2);
    Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4);

    return new Guid(guidArray);
}

首先,对于*1),将更近的日期作为baseDate 不是更好,例如2000-01-01,以便为将来的更多值腾出空间吗?

关于 *2),当我们只对日期时间的字节感兴趣并且从不打算将值存储在 SQL Server 日期时间字段中时,为什么我们要关心 SQL Server 中日期时间的准确性?使用 DateTime.Now 提供的所有准确性不是更好吗?

4

2 回答 2

4

回复 1:与实际天值无关,从该值中使用的两个字节只是在 1900 年 1 月 1 日之后翻转 65536 天。唯一重要的是这些值大致是连续的。dbase 在 2079 年夏天会有点低效,没人会注意到。

回复 2:是的,没有意义。但同样的故事,实际价值并不重要。

该算法是有问题的,弄乱Guids保证的唯一性是一个棘手的命题。您将不得不依赖 nHibernate 团队中具有内部知识的人员,该人员知道这可以正常工作。如果你改变它,你可能会破坏它。

于 2010-04-14T14:49:22.860 回答
1

COMB 是专门为有效地将 GUID 用作 SQL Server 中的聚集索引而创建的。这就是它围绕 SQL Server 特定行为编写的原因。

我参加这个聚会很晚了,但我想我会分享 COMB 的初衷。

我在 04 年开始使用 nHibernate,我们想为我们的 ID 使用 GUID。经过一些研究,我发现 SQL Server 在使用完全随机的 GUID 作为主键/聚集索引方面效率不高,因为它想要按顺序存储它们并且必须插入到表的中间(页面拆分)。我从这篇文章中得到了 COMB 的算法: Jimmy Nilsson 的http://www.informit.com/articles/article.aspx?p=25862,它非常全面地描述了为什么 COMB 是它们现在的样子(并且很好读)。我开始使用自定义生成器来生成 COMB,NHibernate 将它作为内置生成器拾取。

COMB 可能不会在其他服务器中生成有序 ID。我从来没有研究过它。

于 2013-11-13T15:32:16.767 回答