可以在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中的DateTimes的准确性,当我们只对datetime的字节感兴趣时,从不打算将值存储在SQL Server datetime字段中?使用DateTime.Now提供的所有准确度不是更好吗?
答案 0 :(得分:4)
Re 1:与实际日期值无关,从该值中使用的两个字节仅在19,1 / 1/00之后滚动65536天。唯一重要的是价值大致是连续的。在2079年的夏天,dbase的效率会有点低,没有人会注意到。
回复2:是的,没有意义。但同样的道理,实际价值并不重要。
算法值得怀疑,搞乱Guids的保证唯一性是一个棘手的主张。你必须依赖nHibernate团队中的某个人,他们知道这个工作没有问题。如果你改变它,你可能会破坏它。
答案 1 :(得分:1)
COMB是专门为在SQL Server中有效使用GUID作为聚簇索引而创建的。这就是为什么它是围绕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。我从来没有研究过它。