0

众所周知,在具有聚集索引的列中使用随机值并不是一个好主意,这就是为什么通常不建议将 GUID 用于具有聚集索引的主键的原因。使用 newsequentialid() 函数,我们可以克服大部分困难。

但是,如果您在 Web 服务器场上生成 GUID,所有这些都访问同一个数据库,会发生什么情况?我正在使用 UuidCreateSequential 在 .NET 代码中创建顺序 ID,如本文所述:http: //blogs.msdn.com/b/dbrowne/archive/2012/07/03/how-to-generate-sequential-guids-for -sql-server-in-net.aspx

问题是,虽然生成的 GUID 从单台机器上是连续的,但在多台机器上却不是这样。因为最重要的 11 个字节(根据 SQL Server)似乎对于同一台机器几乎保持不变,所以它有效地按机器排序,然后按时间排序,而不是期望的相反。

重新排序 GUID 中的字节以在机器之间获得近乎顺序的 GUID 是否值得且可行,还是我应该放弃并使索引不聚集?

谢谢!

4

2 回答 2

1

在尝试了这个之后,我将回答我自己的问题,并说从问题中描述的多台机器生成顺序 GUID(COMB GUID)不是问题。本质上,每台机器都有一个单独的 ID 序列,这不会导致页面拆分,因为它们将附加到不同页面的末尾,而不是在页面中间(因为新 ID 将始终是最大的按其顺序)。

虽然 GUID 可能不如 int 高效,但我在使用这种方法(每个表有数百万行)时没有遇到任何问题。

于 2016-08-14T00:39:51.023 回答
0

你也可以在c#上生成你的id,看看这个关于代码项目的帖子prb是这个实现生成的代码与NEWSEQUENTIALID生成的不匹配,因为我的目标是c#代码会生成最后6个Guid 的字节作为 Sql 服务器的 NewSequentialID 函数,我最终得到以下代码。

public static Guid ToSequentialAtEnd(this Guid guid)
{
    byte[] guidArray = guid.ToByteArray();

    DateTime now = DateTime.UtcNow;
    var baseDate = new DateTime(1900, 1, 1);

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

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

    // 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);
}
于 2016-08-15T19:27:20.210 回答