关于 NHibernate 的 GuidCombGenerator 的几个问题

发布于 2024-08-29 00:57:43 字数 1348 浏览 4 评论 0原文

以下代码可以在 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),使用更新的日期作为基准日期不是更好吗,例如2000-01-01,这样才能为未来更多的价值腾出空间?

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

The following code can be found in the NHibernate.Id.GuidCombGenerator class. The algorithm creates sequential (comb) guids based on combining a "random" guid with a DateTime. I have a couple of questions related to the lines that I have marked with *1) and *2) below:

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);
}

First of all, for *1), wouldn't it be better to have a more recent date as the baseDate, e.g. 2000-01-01, so as to make room for more values in the future?

Regarding *2), why would we care about the accuracy for DateTimes in SQL Server, when we only are interested in the bytes of the datetime anyway, and never intend to store the value in an SQL Server datetime field? Wouldn't it be better to use all the accuracy available from DateTime.Now?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你如我软肋 2024-09-05 00:57:43

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

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

该算法是有问题的,扰乱 Guid 的唯一性保证是一个棘手的命题。您必须依赖 nHibernate 团队中具有内部知识的人员来确保这可以正常工作。如果你改变它,你很可能会破坏它。

Re 1: there is no relevance to the actual day value, the two bytes used from the value simply roll over 65536 days after 1/1/1900. The only thing that matters is that the values are roughly sequential. The dbase is going to be a bit inefficient in the summer of 2079, nobody will notice.

Re 2: yes, makes no sense. But same story, the actual value doesn't matter.

The algorithm is questionable, messing with the guaranteed uniqueness of Guids is a tricky proposition. You'll have to rely on somebody in the nHibernate team having insider knowledge that this works without problems. If you change it, you're liable to break it.

忘羡 2024-09-05 00:57:43

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

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

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

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

COMB was created specifically to efficiently use GUIDs as a clustered index in SQL Server. That's why it's written around SQL Server specific behavior.

I'm very late to this party but I thought I'd share the original intent of COMB.

I started using nHibernate in '04 and we wanted to use GUIDs for our IDs. After some research I found that SQL Server was not efficient at using completely random GUIDs as a primary key / clustered index because it wanted to store them in order and would have to do insert into the middle of the table (page splits). I got the algorithm for COMB from this article: http://www.informit.com/articles/article.aspx?p=25862 by Jimmy Nilsson which is a very comprehensive description of why COMBs are the way they are (and a good read). I started using a custom generator to generate COMBs and them NHibernate picked it up as a built-in generator.

COMB may not produce in-order IDs in other servers. I've never researched it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文