【问题标题】:Clustered GUID column and newsequentialid across servers跨服务器的集群 GUID 列和 newsequentialid
【发布时间】:2015-12-20 00:14:41
【问题描述】:

众所周知,在具有聚集索引的列中使用随机值并不是一个好主意,这就是为什么通常不建议将 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 是否值得且可行,或者我应该放弃并使索引非集群化吗?

谢谢!

【问题讨论】:

  • Any 基于 GUID 的聚集索引(主键或其他)是一个坏主意,原因正是您在此处概述的原因。仅仅为了维护一个半任意的排序顺序而创建额外的工作对我来说似乎是一种浪费。为什么不直接建立一个更明智的聚集索引?
  • 如果您只是要使用顺序 GUID,为什么还要打扰它们呢?它们占用了大量存储空间,现在它们完全可以预测和重复。
  • @SeanLange:原因是从代码中控制ID,这很方便/实用,尤其是在基于DDD的架构中。
  • @alroc:我认为维护基于主 GUID 键的聚集索引可能会带来一些性能优势,如果这些键按自然顺序排列(即相关行可能靠得很近)
  • 适合集群键的候选者是小的、唯一的和单调的。我猜三分之一的人还不错。 ;) 如果您一心想要使用 GUID,您可以让它们成为非集群主键,而沼泽标准标识列成为您的集群键。

标签: sql-server guid uuid clustered-index newsequentialid


【解决方案1】:

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

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

【讨论】:

【解决方案2】:

你也可以在 c# 上生成你的 id,看看this post on code project prb 是这个实现生成的代码与 NEWSEQUENTIALID 生成的不匹配,因为我的目标是 c# 代码将生成最后一个6个字节的Guid作为Sql server的Ne​​wSequentialID函数,我最终得到如下代码。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-19
    • 1970-01-01
    • 1970-01-01
    • 2016-04-06
    • 2013-10-13
    • 1970-01-01
    相关资源
    最近更新 更多