Sql server SQLServer上COMB GUID处的时间戳为8字节或时间戳为6字节

Sql server SQLServer上COMB GUID处的时间戳为8字节或时间戳为6字节,sql-server,database,guid,Sql Server,Database,Guid,多亏了这篇精彩的文章,我们才有了答案。根据目前的实施情况,有两种方法: 使用最后6个字节作为时间戳: 使用windows勾号将最后8个字节用作时间戳: 我们都知道,对于GUID上的6字节时间戳,随机字节会有更多的字节,以减少GUID的冲突。但是,将创建更多具有相同时间戳的GUID,并且这些GUID根本不是顺序的。因此,最好使用8字节的时间戳 因此,这似乎是一个艰难的选择。根据上面的文章,它说: 在我们继续之前,先给我们一个关于这种方法的简短脚注:使用1毫秒分辨率的时间戳意味着非常紧密地生成的gu

多亏了这篇精彩的文章,我们才有了答案。根据目前的实施情况,有两种方法:

  • 使用最后6个字节作为时间戳:
  • 使用windows勾号将最后8个字节用作时间戳:
  • 我们都知道,对于GUID上的6字节时间戳,随机字节会有更多的字节,以减少GUID的冲突。但是,将创建更多具有相同时间戳的GUID,并且这些GUID根本不是顺序的。因此,最好使用8字节的时间戳

    因此,这似乎是一个艰难的选择。根据上面的文章,它说:

    在我们继续之前,先给我们一个关于这种方法的简短脚注:使用1毫秒分辨率的时间戳意味着非常紧密地生成的guid可能具有相同的时间戳值,因此不会是连续的。这在某些应用程序中可能很常见,事实上,我尝试了一些替代方法,例如使用更高分辨率的计时器,如System.Diagnostics.Stopwatch,或者将时间戳与“计数器”相结合,以确保序列持续到时间戳更新为止。然而,在测试过程中,我发现这根本没有明显的区别,即使在同一个一毫秒窗口内生成了几十个甚至数百个guid。这与Jimmy Nilsson在使用COMBs进行测试时遇到的情况一致

    只是想知道,是否有人谁知道数据库内部可以分享一些关于上述观察灯。是不是因为数据库服务器只是将数据存储在内存中,只有当数据达到某个阈值时才写入磁盘?因此,使用具有相同时间戳的非序列GUID对插入数据进行重新排序通常会在内存中发生,因此性能损失最小

    更新:
    根据我们的测试,与随机GUID相比,梳状GUID不能减少在internet上声称的表碎片。现在唯一的方法似乎是使用SQL Server生成顺序GUID

    你提到的那篇文章是2002年的,非常古老。只需使用即可(在SQLServer2005及更高版本中提供)。这保证了您生成的每个新id都大于上一个id,从而解决了索引碎片/页面分割问题

    不过,我想提到的另一个方面是,那篇文章的作者掩盖了这一点,即在只需要4个字节的情况下使用16个字节不是一个好主意。假设有一个表,其中500000行平均150字节,不包括聚集列,该表有3个非聚集索引(在每行中重复聚集列),每一行平均4字节、25字节和50字节,不包括聚集列

    完美100%填充因子下的存储要求如下(除%外,所有数字均以兆字节为单位):

    在只有一列4字节的
    int
    非聚集索引中(一种常见情况),将聚集索引切换到
    int
    会使其小60%!这将直接转化为表上任何扫描的60%性能改进——这是保守的,因为行越小,页面拆分的频率越低,碎片化的时间越长

    即使在聚集索引本身中,仍然有7.2%的性能改进,这根本不是什么

    如果您在整个数据库中使用
    GUID
    s,该数据库中的表具有与此类似的配置文件,其中切换到
    int
    将减少16.5%的大小,而数据库本身的大小为1.397TB,该怎么办?您的整个数据库将大230 Gb(请参阅总计列139.7-116.7)。这在现实世界中转化为高可用性存储的实际成本。它会提前移动您的磁盘购买计划,这对您公司的底线是有害的

    永远不要使用比需要更大的数据类型。这就像是无缘无故地给你的汽车增加重量:你会为此付出代价(如果不是速度,那么是燃油经济性)

    更新

    现在我知道您正在客户端代码中创建GUID,我可以更清楚地看到问题的本质。如果您可以推迟到行插入时再创建GUID,那么这里有一种方法可以实现这一点

    首先,为
    CustomerID
    列设置默认值:

    ALTER TABLE dbo.Customer ADD CONSTRAINT DF_Customer_CustomerID
       DEFAULT (newsequentialid()) FOR Customer;
    
    现在,您不必在任何
    insert
    中指定要为
    CustomerID
    插入的值,您的查询可能如下所示:

    DECLARE @Name varchar(100) = 'Acme Spy Devices';
    INSERT dbo.Customer (Name)
    OUTPUT inserted.CustomerID -- a GUID
    VALUES (@Name);
    
    在这个非常简单的示例中,您在
    Customer
    表中插入了一个新行,并在一个查询中向客户机返回了一个包含刚刚创建的值的行集


    如果您想显式插入
    值(newsequentialid(),@Name)
    ,也可以。

    非常感谢。我们正在使用实体框架,我们正在使用代码为PK生成GUID,因此我们正在寻找一些最小的代码更改来在代码处生成顺序GUID。此时,由于代码更改太多,我们将无法返回INT作为PK。如果我们使用newsequentialid,那么生成该GUID将需要额外的数据库往返,对吗?正确,
    newsequentialid()
    必须从数据库中调用。有时代码可以在插入整个记录后重写以获取ID,而不必在插入之前获取ID——如果是这样,就不需要额外访问数据库。再次感谢。不知道您是否可以在不需要额外访问数据库的情况下共享一些链接或代码示例。您的磁盘空间计算没有考虑空闲空间。是的,@GreenstoneWalker,它有意不提供实际空间使用情况的精确计算(注意我说的“完美100%填充因子”),这只是为了对两个立柱的空间要求进行合理比较。您如何预测“考虑闲置sp”
    DECLARE @Name varchar(100) = 'Acme Spy Devices';
    INSERT dbo.Customer (Name)
    OUTPUT inserted.CustomerID -- a GUID
    VALUES (@Name);