简体   繁体   English

顺序 GUID

[英]Sequential GUIDs

I hope someone can answer this question.我希望有人能回答这个问题。

How does the UuidCreateSequential method in the rpcrt4.dll class use to seed it's guids? rpcrt4.dll 类中的 UuidCreateSequential 方法如何用于为它的 guid 播种?

I know this much: Microsoft changed the UuidCreate function so it no longer uses the machine's MAC address as part of the UUID.我知道的很多:Microsoft 更改了 UuidCreate 函数,因此它不再使用机器的 MAC 地址作为 UUID 的一部分。 Since CoCreateGuid calls UuidCreate to get its GUID, its output also changed.由于 CoCreateGuid 调用 UuidCreate 以获取其 GUID,因此其输出也发生了变化。 If you still like the GUIDs to be generated in sequential order (helpful for keeping a related group of GUIDs together in the system registry), you can use the UuidCreateSequential function.如果您仍然喜欢按顺序生成 GUID(有助于在系统注册表中将一组相关的 GUID 保持在一起),您可以使用 UuidCreateSequential 函数。

The reason behind the question is.问题背后的原因是。 If I use this function to generate sequential GUIDs in a web cluster, how can I ensure that the GUIDs are close to a range of GUIDs without the potential of the GUID being duplicated?如果我使用此函数在 Web 集群中生成顺序 GUID,我如何确保 GUID 接近某个范围的 GUID 而不会出现 GUID 被复制的可能性?

The Win32 UuidCreateSequential creates a Version 1 uuid . Win32 UuidCreateSequential创建一个Version 1 uuid

Here's some sample version 1 uuid's created on my computer using UuidCreateSequential :这是在我的计算机上使用UuidCreateSequential创建的一些示例版本 1 uuid:

GuidToString                            Raw bytes
======================================  =================================================
{1BE8D85D-63D1-11E1-80DB-B8AC6FBE26E1}  1B E8 D8 5D 63 D1 11 E1  80 DB  B8 AC 6F BE 26 E1
{1BE8D85E-63D1-11E1-80DB-B8AC6FBE26E1}  1B E8 D8 5E 63 D1 11 E1  80 DB  B8 AC 6F BE 26 E1
{1BE8D85F-63D1-11E1-80DB-B8AC6FBE26E1}  1B E8 D8 5F 63 D1 11 E1  80 DB  B8 AC 6F BE 26 E1
{1BE8D860-63D1-11E1-80DB-B8AC6FBE26E1}  1B E8 D8 60 63 D1 11 E1  80 DB  B8 AC 6F BE 26 E1
{1BE8D861-63D1-11E1-80DB-B8AC6FBE26E1}  1B E8 D8 61 63 D1 11 E1  80 DB  B8 AC 6F BE 26 E1
{1BE8D862-63D1-11E1-80DB-B8AC6FBE26E1}  1B E8 D8 62 63 D1 11 E1  80 DB  B8 AC 6F BE 26 E1
{1BE8D863-63D1-11E1-80DB-B8AC6FBE26E1}  1B E8 D8 63 63 D1 11 E1  80 DB  B8 AC 6F BE 26 E1
{1BE8D864-63D1-11E1-80DB-B8AC6FBE26E1}  1B E8 D8 64 63 D1 11 E1  80 DB  B8 AC 6F BE 26 E1
{1BE8D865-63D1-11E1-80DB-B8AC6FBE26E1}  1B E8 D8 65 63 D1 11 E1  80 DB  B8 AC 6F BE 26 E1
{220FB46C-63D1-11E1-80DB-B8AC6FBE26E1}  22 0F B4 6C 63 D1 11 E1  80 DB  B8 AC 6F BE 26 E1

The first thing that's important to note that these uuid contain my machine's MAC address ( B8AC6FBE26E1 ):首先要注意这些 uuid 包含我机器的 MAC 地址( B8AC6FBE26E1 ):

在此处输入图像描述

                        Node
======================= ============
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

So if you're hoping for different computers to generate guid's that are "close" to each other, you're going to be disappointed.因此,如果您希望不同的计算机生成彼此“接近”的 guid,您将会失望。

Let's look at the rest of the values.让我们看看其余的值。

Seven and a half bytes of the remaining 10 bytes are a timestamp ;其余10个字节中的7个半字节是时间戳 the number of 100ns intervals since 00:00:00 15 October 1582 .1582 年 10 月 15 日 00:00:00以来的 100ns 间隔数。 Rearranging those timestamp bytes together:将这些时间戳字节重新排列在一起:

Timestamp              Node
=============== ====== ============
1E163D11BE8D85D 1-80DB B8AC6FBE26E1
1E163D11BE8D85E 1-80DB B8AC6FBE26E1
1E163D11BE8D85F 1-80DB B8AC6FBE26E1
1E163D11BE8D860 1-80DB B8AC6FBE26E1
1E163D11BE8D861 1-80DB B8AC6FBE26E1
1E163D11BE8D862 1-80DB B8AC6FBE26E1
1E163D11BE8D863 1-80DB B8AC6FBE26E1
1E163D11BE8D864 1-80DB B8AC6FBE26E1
1E163D11BE8D865 1-80DB B8AC6FBE26E1
1E163D1220FB46C 1-80DB B8AC6FBE26E1

You can see that guid's created on the same machine by UuidCreateSequential will be together, as they are chronological.您可以看到UuidCreateSequential在同一台机器上创建的 guid 将在一起,因为它们是按时间顺序排列的。


The 1 you see is the version number , in this case meaning a time based uuid.您看到的1版本号,在本例中表示基于时间的uuid。 There are 5 defined versions:有 5 个定义的版本:

Giving:给予:

Timestamp       Version      Node
=============== ======= ==== ============
1E163D11BE8D85D 1       80DB B8AC6FBE26E1
1E163D11BE8D85E 1       80DB B8AC6FBE26E1
1E163D11BE8D85F 1       80DB B8AC6FBE26E1
1E163D11BE8D860 1       80DB B8AC6FBE26E1
1E163D11BE8D861 1       80DB B8AC6FBE26E1
1E163D11BE8D862 1       80DB B8AC6FBE26E1
1E163D11BE8D863 1       80DB B8AC6FBE26E1
1E163D11BE8D864 1       80DB B8AC6FBE26E1
1E163D11BE8D865 1       80DB B8AC6FBE26E1
1E163D1220FB46C 1       80DB B8AC6FBE26E1

The last word contains two things.最后一个包含两件事。

The lower 12 bits is the machine-specifc Clock Sequence number:低 12 位是机器特定的时钟序列号:

Timestamp       Version   Clock Sequence   Node
=============== ======= = ================ ============
1E163D11BE8D85D 1       8 0DB              B8AC6FBE26E1
1E163D11BE8D85E 1       8 0DB              B8AC6FBE26E1
1E163D11BE8D85F 1       8 0DB              B8AC6FBE26E1
1E163D11BE8D860 1       8 0DB              B8AC6FBE26E1
1E163D11BE8D861 1       8 0DB              B8AC6FBE26E1
1E163D11BE8D862 1       8 0DB              B8AC6FBE26E1
1E163D11BE8D863 1       8 0DB              B8AC6FBE26E1
1E163D11BE8D864 1       8 0DB              B8AC6FBE26E1
1E163D11BE8D865 1       8 0DB              B8AC6FBE26E1
1E163D1220FB46C 1       8 0DB              B8AC6FBE26E1

This machine-wide persistent value is incremented if:如果出现以下情况,则此机器范围内的持久值会增加:

  • you switched network cards你换了网卡
  • you generated a UUID less than 100 ns from the last one (and the timestamp would collide)您从上一个生成的 UUID 小于 100 ns(并且时间戳会发生冲突)

So, again, any guid's created by UuidCreateSequential will (ideally) have the same Clock Sequence number, making them "near" to each other.因此,再一次,由UuidCreateSequential创建的任何 guid 将(理想情况下)具有相同的时钟序列号,使它们彼此“接近”。

The final 2 bits, is called a Variant , and is always set to binary 10 :最后 2 位称为Variant ,并且始终设置为二进制10

Timestamp       Version Variant Clock Sequence   Node
=============== ======= ======= ================ ============
1E163D11BE8D85D 1       8       0DB              B8AC6FBE26E1
1E163D11BE8D85E 1       8       0DB              B8AC6FBE26E1
1E163D11BE8D85F 1       8       0DB              B8AC6FBE26E1
1E163D11BE8D860 1       8       0DB              B8AC6FBE26E1
1E163D11BE8D861 1       8       0DB              B8AC6FBE26E1
1E163D11BE8D862 1       8       0DB              B8AC6FBE26E1
1E163D11BE8D863 1       8       0DB              B8AC6FBE26E1
1E163D11BE8D864 1       8       0DB              B8AC6FBE26E1
1E163D11BE8D865 1       8       0DB              B8AC6FBE26E1
1E163D1220FB46C 1       8       0DB              B8AC6FBE26E1

So there you have it.所以你有它。 Sequential guid's are sequential;顺序 guid 是顺序的; and if you create them on the same machine they will be "near" to each other in a database.如果您在同一台机器上创建它们,它们将在数据库中彼此“接近”。


But you want to know what actually happens with two sequential UUID's created on different computers.但是您想知道在不同计算机上创建的两个连续 UUID 实际发生了什么。

Using our newfound knowledge of Version 1 guids, let's construct two guid's for the same timestamp from different machines, eg:使用我们对版本 1 guid 的新知识,让我们为来自不同机器的相同时间戳构造两个 guid,例如:

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

First let's insert a bunch of guid's with sequential timestamps.首先让我们插入一堆带有顺序时间戳的 guid。 First create a temporary table to store our guid's in, and cluster by the guid:首先创建一个临时表来存储我们的guid,并根据guid进行集群

--DROP table #uuidOrderingTest
CREATE TABLE #uuidOrderingTest
( 
    uuid uniqueidentifier not null
)

CREATE clustered index IX_uuidorderingTest_uuid ON #uuidOrderingTest 
( 
   uuid
)

Now insert the data:现在插入数据:

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

Note: i insert them in random timestamp order, to illustrate that SQL Server will cluster them.注意:我以随机时间戳顺序插入它们,以说明 SQL Server 将它们聚类。

Get the rows back and see what order they're in sequential (timestamp) order:取回行并查看它们的顺序(时间戳)顺序:

SELECT * FROM #uuidOrderingTest

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
1BE8D866-63D1-11E1-80DB-B8AC6FBE26E1

Now lets insert guid's with:现在让我们插入 guid:

  • the same timestamps相同的时间戳
  • but different node (ie MAC address):但不同的节点(即MAC地址):

Insert the new guids from a "different" computer:从“不同的”计算机插入新的 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}')

And get the results:并得到结果:

uuid
------------------------------------
1BE8D85D-63D1-11E1-80DB-123456789ABC
1BE8D85E-63D1-11E1-80DB-123456789ABC
1BE8D85F-63D1-11E1-80DB-123456789ABC
1BE8D860-63D1-11E1-80DB-123456789ABC
1BE8D861-63D1-11E1-80DB-123456789ABC
1BE8D862-63D1-11E1-80DB-123456789ABC
1BE8D863-63D1-11E1-80DB-123456789ABC
1BE8D864-63D1-11E1-80DB-123456789ABC
1BE8D865-63D1-11E1-80DB-123456789ABC
1BE8D866-63D1-11E1-80DB-123456789ABC
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
1BE8D866-63D1-11E1-80DB-B8AC6FBE26E1

So there you have it.所以你有它。 SQL Server order's Node before Timestamp . SQL Server 订单的Node before Timestamp Uuid created from different machines will not be clustered together.从不同机器创建的 Uuid 不会聚集在一起。 Would have been better if it hadn't done so, but whatcha gonna do.如果它没有这样做会更好,但你会怎么做。

Rather than rely on the Win32 API, I typically use my own variant of a sequential guid which replaces eight bytes of the a standard guid with ticks from a datetime.我通常不依赖 Win32 API,而是使用我自己的顺序 guid 变体,它将标准 guid 的八个字节替换为日期时间的刻度。

var guidBinary = new byte[16];
Array.Copy( Guid.NewGuid().ToByteArray(), 0, guidBinary, 0, 8 );
Array.Copy( BitConverter.GetBytes( DateTime.Now.Ticks ), 0, guidBinary, 8, 8 );
return new Guid( guidBinary );

I changed Thomas, answer to have first 8 bytes as incremental我改变了 Thomas,答案是将前 8 个字节作为增量

 var guidBinary = new byte[16];
 Array.Copy(BitConverter.GetBytes(DateTime.Now.Ticks), 0, guidBinary, 0, 8);
 Array.Copy(Guid.NewGuid().ToByteArray(), 8, guidBinary, 8, 8);
 return new Guid(guidBinary);

and result will be something like结果会是这样的

b0c99468-714a-08d4-88bd-39e0b53455fb
b122b4b8-714a-08d4-9b12-924e850ad2fe
b1254cf0-714a-08d4-b7c9-954d36290ce5
b12573ff-714a-08d4-b000-632c3a58874d

Not sure about the Win32 way, but you could use the 'undocumented' ' newSequentialID() ' in MSSQL, if you have MSSQL Database connectivity.不确定 Win32 方式,但如果您具有 MSSQL 数据库连接,则可以在 MSSQL 中使用“未记录”的“ newSequentialID() ”。

I Say 'undocumented' because it's treated as incorrect when trying to save it as the default value for a MSSQL Identity column, and you have to override it and say you want to use it.我说“未记录”是因为在尝试将其保存为 MSSQL 身份列的默认值时它被视为不正确,您必须覆盖它并说您想要使用它。

You could have a central table that has the last known starting UID for a range and increment it.您可以拥有一个中央表,其中包含某个范围的最后一个已知起始 UID 并递增它。

eg: DB1 creates a GUID {AA333F14-FCCD-4bee-9F8F-9D9BDF1B8766} and writes this to the table.例如:DB1 创建一个 GUID {AA333F14-FCCD-4bee-9F8F-9D9BDF1B8766} 并将其写入表中。 DB2 comes online and sees {AA333F14-FCCD-4bee-9F8F-9D9BDF1B8766} and increments it by some set number, like 1,000,000,000,000,000 or something really high so you won't have any overlapping values. DB2 上线并看到 {AA333F14-FCCD-4bee-9F8F-9D9BDF1B8766} 并将其递增某个设定数字,例如 1,000,000,000,000,000 或非常高的值,因此您不会有任何重叠值。

But really, GUIDs are almost useless when used incrementally.但实际上,GUID 在增量使用时几乎毫无用处。

I guess the really question is, what are you using GUIDs for?我想真正的问题是,您使用 GUID 是为了什么? If you want an incrmenting number, just use a 64bit int(aka, bigint)如果你想要一个递增的数字,只需使用 64 位 int(又名 bigint)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM