C# · 12月 26, 2021

c# – 顺序GUID

我希望有人可以回答这个问题.

如何使用rpcrt4.dll类中的UuidCreateSequential方法种子它的guids?

我知道很多:
Microsoft更改了UuidCreate功能,因此它不再使用机器的MAC地址作为UUID的一部分.由于CoCreateGuid调用UuidCreate获取其GUID,其输出也改变了.如果您仍然按照顺序生成GUID(有助于将相关的GUID组保存在系统注册表中),则可以使用UuidCreateSequential函数.

问题背后的原因是.如果我使用此功能在Web集群中生成顺序GUID,那么如何确保GUID接近一系列GUID,而不会重复GUID?

解决方法 Win32 UuidCreateSequential创建一个 Version 1 uuid.

以下是使用UuidCreateSequential在我的电脑上创建的一些示例版本1 uuid:

{1BE8D85D-63D1-11E1-80DB-B8AC6FBE26E1}{1BE8D85E-63D1-11E1-80DB-B8AC6FBE26E1}{1BE8D85F-63D1-11E1-80DB-B8AC6FBE26E1}{1BE8D860-63D1-11E1-80DB-B8AC6FBE26E1}{1BE8D861-63D1-11E1-80DB-B8AC6FBE26E1}{1BE8D862-63D1-11E1-80DB-B8AC6FBE26E1}{1BE8D863-63D1-11E1-80DB-B8AC6FBE26E1}{1BE8D864-63D1-11E1-80DB-B8AC6FBE26E1}{1BE8D865-63D1-11E1-80DB-B8AC6FBE26E1}{220FB46C-63D1-11E1-80DB-B8AC6FBE26E1}

首先要注意的是,这些uuid包含我的机器的MAC地址(B8AC6FBE26E1):

Node======================= ============1BE8D85D-63D1-11E1-80DB B8AC6FBE26E11BE8D85E-63D1-11E1-80DB B8AC6FBE26E11BE8D85F-63D1-11E1-80DB B8AC6FBE26E11BE8D860-63D1-11E1-80DB B8AC6FBE26E11BE8D861-63D1-11E1-80DB B8AC6FBE26E11BE8D862-63D1-11E1-80DB B8AC6FBE26E11BE8D863-63D1-11E1-80DB B8AC6FBE26E11BE8D864-63D1-11E1-80DB B8AC6FBE26E11BE8D865-63D1-11E1-80DB B8AC6FBE26E1220FB46C-63D1-11E1-80DB B8AC6FBE26E1

所以如果你希望不同的计算机产生相互“接近”的指针,那么你将会失望.

我们来看看其余的值.

其余10个字节的七个半字节是时间戳;从00:00:00 1582年10月15日起的间隔时间为100ns.将这些时间戳记字节重新排列在一起:

Timestamp Node=============== ====== ============1E163D11BE8D85D 1-80DB B8AC6FBE26E11E163D11BE8D85E 1-80DB B8AC6FBE26E11E163D11BE8D85F 1-80DB B8AC6FBE26E11E163D11BE8D860 1-80DB B8AC6FBE26E11E163D11BE8D861 1-80DB B8AC6FBE26E11E163D11BE8D862 1-80DB B8AC6FBE26E11E163D11BE8D863 1-80DB B8AC6FBE26E11E163D11BE8D864 1-80DB B8AC6FBE26E11E163D11BE8D865 1-80DB B8AC6FBE26E11E163D1220FB46C 1-80DB B8AC6FBE26E1

您可以看到,由UuidCreateSequential在同一台机器上创建的GUID将在一起,因为它们是按时间顺序的.

你看到的1是版本号,在这种情况下是一个基于时间的uuid.有5个定义的版本:

> 1:基于时间的版本(UuidCreateSequential)
> 2:DCE安全版本,带有嵌入式POSIX UID
> 3:使用MD5散列的基于名称的版本
> 4:随机或伪随机生成的版本(UuidCreate)
> 5:使用SHA-1散列的基于名称的版本

赠送:

Timestamp Version Node=============== ======= ==== ============1E163D11BE8D85D 1 80DB B8AC6FBE26E11E163D11BE8D85E 1 80DB B8AC6FBE26E11E163D11BE8D85F 1 80DB B8AC6FBE26E11E163D11BE8D860 1 80DB B8AC6FBE26E11E163D11BE8D861 1 80DB B8AC6FBE26E11E163D11BE8D862 1 80DB B8AC6FBE26E11E163D11BE8D863 1 80DB B8AC6FBE26E11E163D11BE8D864 1 80DB B8AC6FBE26E11E163D11BE8D865 1 80DB B8AC6FBE26E11E163D1220FB46C 1 80DB B8AC6FBE26E1

最后一句话包含两件事.

低12位是机器特定的时钟序列号:

Timestamp Version Clock Sequence Node=============== ======= = ================ ============1E163D11BE8D85D 1 8 0DB B8AC6FBE26E11E163D11BE8D85E 1 8 0DB B8AC6FBE26E11E163D11BE8D85F 1 8 0DB B8AC6FBE26E11E163D11BE8D860 1 8 0DB B8AC6FBE26E11E163D11BE8D861 1 8 0DB B8AC6FBE26E11E163D11BE8D862 1 8 0DB B8AC6FBE26E11E163D11BE8D863 1 8 0DB B8AC6FBE26E11E163D11BE8D864 1 8 0DB B8AC6FBE26E11E163D11BE8D865 1 8 0DB B8AC6FBE26E11E163D1220FB46C 1 8 0DB B8AC6FBE26E1

如果:

你切换网卡
你生成的UUID从最后一个不到100ns(并且时间戳会相撞)

因此,再次,由UuidCreateSequential创建的任何guid将(理想情况下)具有相同的时钟序列号,使它们彼此“靠近”.

最后的2位称为Variant,并且始终设置为二进制10:

Timestamp Version Variant Clock Sequence Node=============== ======= ======= ================ ============1E163D11BE8D85D 1 8 0DB B8AC6FBE26E11E163D11BE8D85E 1 8 0DB B8AC6FBE26E11E163D11BE8D85F 1 8 0DB B8AC6FBE26E11E163D11BE8D860 1 8 0DB B8AC6FBE26E11E163D11BE8D861 1 8 0DB B8AC6FBE26E11E163D11BE8D862 1 8 0DB B8AC6FBE26E11E163D11BE8D863 1 8 0DB B8AC6FBE26E11E163D11BE8D864 1 8 0DB B8AC6FBE26E11E163D11BE8D865 1 8 0DB B8AC6FBE26E11E163D1220FB46C 1 8 0DB B8AC6FBE26E1

所以你有它.顺序方向是顺序的;并且如果您在同一台计算机上创建它们,那么它们将在数据库中彼此“靠近”.

但是您想知道在不同的计算机上创建的两个连续的UUID实际发生了什么.

使用我们对版本1 guids的新发现的知识,让我们从不同的机器构造相同时间戳的两个guid,例如:

{1BE8D85D-63D1-11E1-80DB-B8AC6FBE26E1}{1BE8D85D-63D1-11E1-80DB-123456789ABC}

首先让我们用连续的时间戳插入一堆guid.首先创建一个临时表来存储我们的guid,并通过guid进行聚类:

–DROP table #uuidOrderingTestCREATE TABLE #uuidOrderingTest( uuid uniqueidentifier not null)CREATE clustered index IX_uuidorderingTest_uuid ON #uuidOrderingTest ( uuid)

现在插入数据:

INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D866-63D1-11E1-80DB-B8AC6FBE26E1}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D862-63D1-11E1-80DB-B8AC6FBE26E1}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D861-63D1-11E1-80DB-B8AC6FBE26E1}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D85E-63D1-11E1-80DB-B8AC6FBE26E1}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D864-63D1-11E1-80DB-B8AC6FBE26E1}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D863-63D1-11E1-80DB-B8AC6FBE26E1}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D85F-63D1-11E1-80DB-B8AC6FBE26E1}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D85D-63D1-11E1-80DB-B8AC6FBE26E1}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D865-63D1-11E1-80DB-B8AC6FBE26E1}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D860-63D1-11E1-80DB-B8AC6FBE26E1}’)

注意:我以随机时间戳顺序插入它们,以说明sql Server将它们聚类.

将行返回并查看顺序(时间戳)顺序的顺序:

SELECT * FROM #uuidOrderingTestuuid————————————1BE8D85D-63D1-11E1-80DB-B8AC6FBE26E11BE8D85E-63D1-11E1-80DB-B8AC6FBE26E11BE8D85F-63D1-11E1-80DB-B8AC6FBE26E11BE8D860-63D1-11E1-80DB-B8AC6FBE26E11BE8D861-63D1-11E1-80DB-B8AC6FBE26E11BE8D862-63D1-11E1-80DB-B8AC6FBE26E11BE8D863-63D1-11E1-80DB-B8AC6FBE26E11BE8D864-63D1-11E1-80DB-B8AC6FBE26E11BE8D865-63D1-11E1-80DB-B8AC6FBE26E11BE8D866-63D1-11E1-80DB-B8AC6FBE26E1

现在可以插入guid:

>相同的时间戳
>但不同的节点(即MAC地址):

从“不同”的计算机插入新的guids:

INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D866-63D1-11E1-80DB-123456789ABC}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D862-63D1-11E1-80DB-123456789ABC}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D861-63D1-11E1-80DB-123456789ABC}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D85E-63D1-11E1-80DB-123456789ABC}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D864-63D1-11E1-80DB-123456789ABC}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D863-63D1-11E1-80DB-123456789ABC}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D85F-63D1-11E1-80DB-123456789ABC}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D85D-63D1-11E1-80DB-123456789ABC}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D865-63D1-11E1-80DB-123456789ABC}’)INSERT INTO #uuidOrderingTest (uuid) VALUES (‘{1BE8D860-63D1-11E1-80DB-123456789ABC}’)

并得到结果:

uuid————————————1BE8D85D-63D1-11E1-80DB-123456789ABC1BE8D85E-63D1-11E1-80DB-123456789ABC1BE8D85F-63D1-11E1-80DB-123456789ABC1BE8D860-63D1-11E1-80DB-123456789ABC1BE8D861-63D1-11E1-80DB-123456789ABC1BE8D862-63D1-11E1-80DB-123456789ABC1BE8D863-63D1-11E1-80DB-123456789ABC1BE8D864-63D1-11E1-80DB-123456789ABC1BE8D865-63D1-11E1-80DB-123456789ABC1BE8D866-63D1-11E1-80DB-123456789ABC1BE8D85D-63D1-11E1-80DB-B8AC6FBE26E11BE8D85E-63D1-11E1-80DB-B8AC6FBE26E11BE8D85F-63D1-11E1-80DB-B8AC6FBE26E11BE8D860-63D1-11E1-80DB-B8AC6FBE26E11BE8D861-63D1-11E1-80DB-B8AC6FBE26E11BE8D862-63D1-11E1-80DB-B8AC6FBE26E11BE8D863-63D1-11E1-80DB-B8AC6FBE26E11BE8D864-63D1-11E1-80DB-B8AC6FBE26E11BE8D865-63D1-11E1-80DB-B8AC6FBE26E11BE8D866-63D1-11E1-80DB-B8AC6FBE26E1

所以你有它.时间戳之前的sql Server订单节点.从不同机器创建的Uuid不会聚集在一起.如果没有这样做,会更好,但是whatcha会做.