我应该将前端生成的 UUIDv6 转换为 binary(16) 以在 SQL Server 中用作群集主键吗?

oop*_*oop 5 sql-server clustered-primary-key uuid

背景

根据前端开发人员的建议,我考虑使用 UUID 作为新系统中一堆表的主键。从了解随机 UUID 与顺序 UUID 的优缺点,到将非聚集主键与可排序类型的聚集索引结合使用,我的研究向我指出了UUIDv6及其实现

它能够生成如下所示的 UUID(即顺序的):

UUIDv1 UUIDv6 
------------------------------------ -------------- --------------- 
5714f720-1268-11e7-a24b-96d95aa38c32 1e712685-714f-6720-a23a-c90103f70be6 
68f820c0-1268-11e7-a24b-96d95aa38c32 1e712686-8f82-60c0-ac07-7d6641ed230d 
7ada38f0-1268-11e7-a24b-96d95aa38c32 1e712687-ada3-68f0-93f8-c1ebf8e6fc8c 
8cc06fd0-1268-11e7-a24b-96d95aa38c32 1e712688-cc06-6fd0-a828-671acd892c6a 
9ea6a6b0-1268-11e7-a24b-96d95aa38c32 1e712689-ea6a-66b0-910c-dbcdb07df7a4

我认为 SQL Server 会很乐意在群集主键(唯一标识符)列中为我排序。

我几乎不知道 SQL Server 如何对 uniqueidentifier 列进行排序。这是升序排序结果:

UUIDv6 唯一标识符排序 
--------------------- 
1e712688-cc06-6fd0-a828- 67 1acd892c6a 
1e712686-8f82-60c0-ac07- 7D 6641ed230d 
1e712687-ada3-68f0-93f8- c1 ebf8e6fc8c 
1e712685-714f-6720-a23a- c9 0103f70be6 
1e712689-ea6a-66b0-910c- db cdb07df7a4

这会导致碎片,就像使用随机 UUID 一样。这篇文章解释了它们实际上是如何排序的。

真正的问题

幸运的是,该系统仍在开发中。接下来我应该选择哪些选项?

  1. 重新排序字节,以便最高/最低有效字节是 SQL Server 期望它们所在的位置
UUIDv6 UUIDv6 重新排序的字节 
------------------------------------ -------------- --------------- 
1e712685-714f-6720-a23a-c90103f70be6 c90103f7-0be6-a23a- 6720-1e712685 714f 
1e712686-8f82-60c0-ac07-7d6641ed230d 7d6641ed-230d- ac07-60c0-1e712686 8f82 
1e712687-ada3-68f0-93f8-c1ebf8e6fc8c c1ebf8e6-fc8c- 93f8-68f0-1e712687 ada3 
1e712688-cc06-6fd0-a828-671acd892c6a 671acd89-2c6a- a828-6fd0-1e712688 cc06 
1e712689-ea6a-66b0-910c-dbcdb07df7a4 dbcdb07d-f7a4-910c- 66b0-1e712689 ea6a
  1. 将 UUIDv6 转换为 binary(16) 并改用它
UUIDv6 UUIDv6 二进制 (16) 
------------------------------------ -------------- ------------------ 
1e712685-714f-6720-a23a-c90103f70be6 1e712685 714f6720a23ac90103f70be6 
1e712686-8f82-60c0-ac07-7d6641ed230d 1e712686 8f8260c0ac077d6641ed230d 
1e712687-ada3-68f0-93f8-c1ebf8e6fc8c 1e712687 ada368f093f8c1ebf8e6fc8c 
1e712688-cc06-6fd0-a828-671acd892c6a 1e712688 cc066fd0a828671a​​cd892c6a 
1e712689-ea6a-66b0-910c-dbcdb07df7a4 1e712689 ea6a66b0910cdbcdb07df7a4

有问题 option 1

UUID 标准在 ID 内嵌入了一个 4 位版本字段。UUIDv6(仍然是非标准的)也遵循该规则。我对它们重新排序的方式将打破这一点。

有问题 option 2

我不知道。除了这个,几乎找不到任何人在谈论它,这违背了这个想法。在使用 binary(16) 类型时,还有其他我应该注意的陷阱吗?

谢谢!

Jos*_*ell 6

我会考虑另一种选择:在代理键(如Id int IDENTITY(1,1) NOT NULL)上集群,并使应用程序生成的 UUID 成为非集群主键。

这避免了您在选项 1 和 2 中提到的问题,因为您不必担心基表中的排序/碎片问题,或者在binary.

它还将为您节省一些空间(int 小于uniqueidentifierand binary(16)),因为每个非聚集索引(以及通过外键引用此表的其他表)中都包含聚集键。


Dav*_*oft 3

对字节重新排序,以便最高/最低有效字节位于 SQL Server 期望的位置

去做。

选项 1 是 SQL Server 本身使用 NEWSEQUENTIALID() 执行的操作,如维基百科所述

NEWSEQUENTIALID 函数返回类似于 UUID 的 128 位标识符,这些标识符致力于按顺序升序直到下一次系统重新启动

在 SQL Server 中,UNIQUEIDENTIFIER 只是一个 128 位二进制类型。它不需要符合 UUID 的结构。

如果它是顺序生成的*,您可以将其设为聚集索引键。拥有较窄的聚集索引键通常不值得花费额外的不必要的索引。

*如果连续值的排序顺序中的位置偶尔发生变化或者由几个不同的应用程序服务器在几个不同的位置生成,那么这并不是什么大问题。