C# 是否有一个与SQL Server';s newsequentialid()

C# 是否有一个与SQL Server';s newsequentialid(),c#,.net,sql-server,C#,.net,Sql Server,我们使用guid作为主键,您知道默认情况下主键是集群的 在表中插入新行时,它会插入到表中的随机页面(因为GUID是随机的)。这会对性能产生可测量的影响,因为数据库会一直分割数据页(碎片)。但我之所以知道顺序GUID是什么,主要是因为我希望新行作为表中的最后一行插入。。。这将有助于调试 我可以在CreateDate上创建一个聚集索引,但是我们的数据库是自动生成的,在开发过程中,我们需要做一些额外的事情来促进这一点。而且,CreateDate不是一个很好的聚集索引候选 回到那时,我用过,但我想知道在

我们使用guid作为主键,您知道默认情况下主键是集群的

在表中插入新行时,它会插入到表中的随机页面(因为GUID是随机的)。这会对性能产生可测量的影响,因为数据库会一直分割数据页(碎片)。但我之所以知道顺序GUID是什么,主要是因为我希望新行作为表中的最后一行插入。。。这将有助于调试

我可以在
CreateDate
上创建一个聚集索引,但是我们的数据库是自动生成的,在开发过程中,我们需要做一些额外的事情来促进这一点。而且,
CreateDate
不是一个很好的聚集索引候选

回到那时,我用过,但我想知道在.NET框架中是否有这样的东西。在SQL 2005中,Microsoft引入了
newsequentialid()
,作为
newid()
的替代方案,因此我希望他们能与.NET等效,因为我们在代码中生成ID


PS:请不要开始讨论这是对还是错,因为GUID应该是唯一的等等。

关键问题是知道.NET应用程序中的最后一个值是什么。SQL Server会为您跟踪这一点。您需要自己保存最后一个值,并将Guid构造函数与包含下一个值的字节数组一起使用。当然,在分布式应用程序上,这可能没有帮助,您可能必须使用随机guid。(我并不认为这有什么问题。)


确定行的添加顺序的一种简单方法可能是向表中添加一个标识列,这样就不需要保持GUID的顺序,从而避免了在GUID列上维护聚集索引对性能的影响


我不禁想知道,在调试时,保持这些行的有序性如何帮助您。你能扩展一下吗?

不幸的是,没有一个.NET等价于
newsequentialid()
。你可以继续使用梳子。实际上,我在某个地方有一个Comb的C#实现……我会看看是否可以把它挖出来。

应该可以使用对UuidCreateSequential的API调用在C#或vb.net中创建顺序GUID。下面的API声明(C#)取自其中,您还可以找到如何调用函数的完整示例

[DllImport("rpcrt4.dll", SetLastError=true)]
static extern int UuidCreateSequential(out Guid guid);

与UuidCreateSequential函数相关的MSDN文章可以是,其中包括使用的先决条件。

我一直认为随机GUID在某些用例中有助于提高性能。显然,插入到随机页面可以避免在多人同时尝试插入时在结束页面中发生的争用

John的PInvoke建议可能与SQL的版本最接近,但UUidCreateSequential docs指出,您不应该使用它来标识一个对象,该对象严格地位于生成Guid的机器的本地

在我进一步研究顺序Guid生成之前,我会用实际数量的实际数据测量实际用例的性能

byte[] guidArray = System.Guid.NewGuid().ToByteArray();

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 = new TimeSpan(now.Ticks - (new DateTime(now.Year, now.Month, now.Day).Ticks));

// 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 System.Guid(guidArray);

关于所选答案。医生说。。。如果计算机没有eInternet访问权限,则生成的Guid不会在计算机之间为您提供唯一ID

如果插入时必须知道guid,那么在插入数据之前,是否可以让Sql server返回分配给数据的连续guid块

declare @ids table(id uniqueidentifier default NEWSEQUENTIALID(), dummy char(1))

declare @c int
set @c = 0;
while (@c < 100)
begin
    insert into @ids (dummy) values ('a');
    set @c += 1;
end

select id from @ids
declare@ids表(id uniqueidentifier default NEWSEQUENTIALID(),伪字符(1))
声明@c int
设置@c=0;
而(@c<100)
开始
插入@ids(虚拟)值('a');
设置@c+=1;
结束
从@ids中选择id

2018年更新:同样

这就是NHibernate生成序列ID的方式:

//
///使用comb算法生成一个新的。
/// 
私有Guid GenerateComb()
{
字节[]guidArray=Guid.NewGuid().ToByteArray();
DateTime baseDate=新的日期时间(1900,1,1);
DateTime now=DateTime.now;
//获取将用于构建字节字符串的天数和毫秒
TimeSpan天=新的TimeSpan(now.Ticks-baseDate.Ticks);
TimeSpan毫秒=now.TimeOfDay;
//转换为字节数组
//请注意,SQL Server精确到1/300毫秒,因此我们除以3.333
byte[]daysArray=BitConverter.GetBytes(天.天);
byte[]msecsray=BitConverter.GetBytes((长)(msecs.total毫秒/3.333333));
//反转字节以匹配SQL Server顺序
数组。反向(daysArray);
Array.Reverse(msecsrarray);
//将字节复制到guid中
复制(daysArray,daysArray.Length-2,guidArray,guidArray.Length-6,2);
复制(msecsArray,msecsArray.Length-4,guidArray,guidArray.Length-4,4);
返回新的Guid(guidArray);
}

需要注意的是,生成的UUID在SQL Server排序时不会是顺序的

  • SQL Server在对UUID进行排序时遵循
  • RFC搞错了
  • UuidCreateSequential
    做得对吗
  • 但是
    UuidCreateSequential
    创建了与SQL Server期望的不同的东西
背景 UuidCreateSequential创建的类型1 UUID不会在SQL Server中排序

SQL Server的NewSequentialID使用UuidCreateSequential,并应用了一些字节洗牌。在线图书:

NEWSEQUENTIALID是Windows UuidCreateSequential函数的包装器,具有

然后引用MSDN博客文章:

()

从1582-10-15 00:00:00(1592年10月15日,即 公历改为基督教历法)。Ticks是100 ns间隔的数量

例如:

  • 2017年12月6日UTC下午4:09:39/// <summary> /// Generate a new <see cref="Guid"/> using the comb algorithm. /// </summary> private Guid GenerateComb() { byte[] guidArray = Guid.NewGuid().ToByteArray(); 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; // 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); }
    public static Guid NewSequentialId()
    {
       Guid guid;
       UuidCreateSequential(out guid);
       var s = guid.ToByteArray();
       var t = new byte[16];
    
       t[3] = s[0];
       t[2] = s[1];
       t[1] = s[2];
       t[0] = s[3];
    
       t[5] = s[4];
       t[4] = s[5];
       t[7] = s[6];
       t[6] = s[7];
       t[8] = s[8];
       t[9] = s[9];
       t[10] = s[10];
       t[11] = s[11];
       t[12] = s[12];
       t[13] = s[13];
       t[14] = s[14];
       t[15] = s[15];
    
       return new Guid(t);
    }
    
    0x01E7DA9FDCA45C22
    
    |   Hi   |   Mid  |    Low     |
    |--------|--------|------------|
    | 0x01E7 | 0xDA9F | 0xDCA45C22 |
    
    DC A4 5C 22 DA 9F x1 E7 xx xx xx xx xx xx xx xx
    
    22 5C A4 DC 9F DA E7 x1 xx xx xx xx xx xx xx xx
    
    225CA4DC9FDAE701
    
    DCA45C22-DA9F-11E7-DDDD-FFFFFFFFFFFF
    
    22 5C A4 DC 9F DA E7 11 DD DD FF FF FF FF FF FF
    
    Low      Mid  Version High
    -------- ---- ------- ---- -----------------
    DCA45C22-DA9F-1       1E7 -DDDD-FFFFFFFFFFFF
    
    DC A4 5C 22 DA 9F 11 E7 DD DD FF FF FF FF FF FF
    
                   |   Swap      | Swap  | Swap  | Copy as-is
    Start index    |  0  1  2  3 |  4  5 |  6  7 | 
    End index      |  3  2  1  0 |  5  4 |  7  6 | 
    ---------------|-------------|-------|-------|------------------------ 
    Little-endian: | 22 5C A4 DC | 9F DA | E7 11 | DD DD FF FF FF FF FF FF
    Big-endian:    | DC A4 5C 22 | DA 9F | 11 E7 | DD DD FF FF FF FF FF FF
    
    Install-Package NewId
    
    Guid myNewSequentialGuid =  NewId.NextGuid();