开发者

A couple of questions about NHibernate's GuidCombGenerator

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 开发者_JAVA技巧- 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?


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜