生成的顺序 GUID 有时不是顺序的。

4

我有一个C#应用程序,为每个插入到表中的行生成连续的GUID。我期望插入的GUID是连续的,但有时会出现序列中断的情况(以块为单位)。

例如:

Break in sequence

这些GUID按照插入的顺序显示。
为什么这些“连续的”GUID会有如此大的序列间隔而被创建?
生成顺序 GUID 的代码:

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

public static Guid CreateSequentialGuid()
    {
        const int RPC_S_OK = 0;

        Guid guid;
        int result = NativeMethods.UuidCreateSequential(out guid);
        if (result == RPC_S_OK)
            return guid;
        else
            return Guid.NewGuid(); //<--In debugging, this statement never runs.
    }

用于循环插入新GUID和信息到表中的代码:

Guid mySequentialGUID = CreateSequentialGuid();
string[] row = { item1,
                 item2,
                 item3,  
                 sourceText,
                 encoding.ToString(),
                 mySequentialGUID.ToString()
             };
var listViewItem = new ListViewItem(row);
myListView.Items.Add(listViewItem);

编辑:

请查看此问题以了解顺序 GUID:


4
GUID的存在是为了成为一个唯一的数字,不多不少。虽然有不同的算法可以用于生成它们,但你不应该依赖特定实现的特定属性。将GUID视为GUID,仅此而已。如果你需要一个递增的数字,则应该获取一个数字并将其递增,而不是使用GUID,因为GUID只是生成唯一数字的一种表示方式。 - Servy
3
我从未听说过“连续GUID”,但这似乎完全是错误的。你是自己编的吗?GUID本质上是唯一的,你无法控制它的生成方式。如果你能够知道下一个GUID将会被生成(因为它是从上一个GUID开始的下一个序列),那么它就不再是唯一的,因为其他人也可以使用相同的起始值进行相同的操作。 - rory.ap
3
为什么这很重要呢?只要它们仍然有序,它就能正常工作,索引就不必重新排序。好像它们不会用完值一样 :) - stuartd
3
似乎连续GUID使用系统时间,因此当时钟更新时(大约每15毫秒),可能会出现跳跃。 - Mike Zboray
3
在我看来,“sequential”并不意味着“contiguous”。 - spender
显示剩余6条评论
2个回答

5
我认为问题在于你假设“sequential”意味着“递增一”。尽管你的例子有时会出现这种情况,但是文档中并没有实际保证。我们可以争论“序列”的定义,或者也许这个函数的命名不当,甚至是错误的,但是最终根据文档,它似乎完全按照定义工作100%:
创建一个 GUID ,它比此函数之前生成的任何 GUID 都要大。
对于那些对“顺序 GUID”的概念有问题的人,请使用“按照逻辑顺序跟随”的“序列”定义,并尝试记住 Melissa 病毒。这 通过这行代码略微记录了下来
出于安全原因,UuidCreate 被修改,以不再使用机器的 MAC 地址生成 UUID。引入了 UuidCreateSequential 以允许使用机器的以太网卡的 MAC 地址创建 UUID。
所以,“sequence”是基于 MAC 地址生成 GUID。
回到 OP 的问题上,我最好的猜测是你的 GUID 不是每次递增一的简单事实,很可能是因为你可能不是唯一调用此函数的人。这是一个核心的 Windows 函数,肯定会有其他组件、程序、服务等在使用它。

这个答案是正确的,但我想补充一下,如果OP想要使用结果在SQL Server中插入行,她应该知道UuidCreateSequential与SQL Server的排序顺序不完全相同,并且需要执行一些字节重排:https://blogs.msdn.microsoft.com/dbrowne/2012/07/03/how-to-generate-sequential-guids-for-sql-server-in-net/ - martin

2
NewSequentialId()函数在系统重启时将重新开始计数。请参阅此处

该函数创建一个GUID,其值大于自Windows启动以来在指定计算机上先前生成的任何GUID。在重新启动Windows后,GUID可以从较低范围重新开始,但仍然是全局唯一的。当使用GUID列作为行标识符时,使用NEWSEQUENTIALID可能比使用NEWID函数更快。这是因为NEWID函数会导致随机活动并使用更少的缓存数据页。使用NEWSEQUENTIALID还有助于完全填充数据和索引页面。


谢谢您的回答。我意识到这可能发生在 Windows 重新启动后。我的 CreateSequentialGuid() 方法在一个快速的 for 循环中被调用,而我的机器没有被重新启动。 - Kyle Williamson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接