首页 > 其他分享 >UUIDV7: 我就是要用UUID做主键

UUIDV7: 我就是要用UUID做主键

时间:2024-09-02 17:27:14浏览次数:10  
标签:UUID UUIDv1 UUIDV7 生成 时间 做主 UUIDv6 bits

一直以来的互联网谣言: UUID是不适合用作数据库主键的.

为什么? 因为UUID是全随机的, 对于数据库的索引不友好, 插入时可能导致大量的索引树的分支合并.

UUID

根据RFC4122的描述, UUID被设计用于去中心化的ID生成

格式

128bit, 16个字节, 示例: f81d4fae-7dec-11d0-a765-00a0c91e6bf6

按照8-4-4-4-12的格式进行分配, 每个位置用其16进制编码表示

具体结构如下:


+-------------------------------+
|         128 bits             |
+-------------------------------+
| time_low (32 bits)           |  0 - 31
+-------------------------------+
| time_mid (16 bits)           |  32 - 47
+-------------------------------+
| time_hi_and_version (16 bits) |  48 - 63
+-------------------------------+
| clock_seq_hi_and_reserved (8 bits) |  64 - 71
+-------------------------------+
| clock_seq_low (8 bits)       |  72 - 79
+-------------------------------+
| node (48 bits)               |  80 - 127
+-------------------------------+
  • time_low: 32位(8个十六进制数字)
  • time_mid: 16位(4个十六进制数字)
  • time_hi_and_version: 16位(4个十六进制数字,其中前4位表示版本号)
  • clock_seq_and_reserved: 16位(4个十六进制数字,其中前2位用于标识变体)
  • node: 48位(12个十六进制数字,通常是MAC地址或随机生成的值)

实现

在提案中, 同样提及了三种方式生成UUID

  1. 基于时间的UUID(Version 1)

    • 这种UUID是基于当前的时间戳生成的,时间戳是从1582年10月15日(公历改革的日期)开始的100纳秒间隔计数。

    • 它包含一个节点标识符(通常是设备的MAC地址)以及一个时钟序列,以避免因时钟回拨而导致的重复UUID。

    • 生成过程如下:

      1. 获取当前时间的100纳秒间隔计数。
      2. 获取当前的节点ID。
      3. 生成一个时钟序列,如果时钟回拨或节点ID改变,则更新时钟序列。
      4. 将这些值格式化为UUID的各个部分。
  2. 基于名称的UUID(Version 3和Version 5)

    • 这种UUID是通过对名称(如URL、域名等)进行哈希计算生成的。

    • Version 3使用MD5哈希算法,而Version 5使用SHA-1哈希算法。

    • 生成过程如下:

      1. 为名称分配一个命名空间ID(UUID)。
      2. 将名称转换为标准的八位字节序列,并将命名空间ID以网络字节顺序放置。
      3. 计算命名空间ID与名称的哈希值。
      4. 根据哈希值的特定部分设置UUID的各个字段,包括版本号和时钟序列。
  3. 随机或伪随机UUID(Version 4)

    • 这种UUID是基于随机或伪随机数生成的。

    • 生成过程如下:

      1. 设置UUID的变体字段(clock_seq_hi_and_reserved)和版本字段(time_hi_and_version)。
      2. 将UUID的其他位设置为随机或伪随机生成的值。
      3. 生成的UUID包括了当前的变体和版本信息。

完全随机的V4

其中, V3或者V5使用场景不是很多, V4的使用是最广泛的. 因为其实现方式, 决定了他的随机性是很强的, 几乎不存在空间上的内聚性.

存在时序性的V1

实际上V1已经表现出了时序性, 也就是在时间上的递增性.

但是为什么UUIDV1没有被广泛使用呢?

  1. 隐私问题

    • UUIDv1包含了节点标识符,通常是设备的MAC地址。这意味着生成的UUID可以泄露生成UUID的设备的信息,导致隐私问题。例如,攻击者可以通过UUID推测出特定设备的身份或位置。
  2. 时钟回拨问题

    • UUIDv1依赖系统时间来生成UUID,如果系统的时钟被意外地设置回过去,可能会导致生成重复的UUID。这是一个潜在的冲突风险,尤其是在分布式系统中,多个节点可能会同时生成UUID。
  3. 跨设备的唯一性问题

    • 随着设备移动或更换网络,MAC地址可能会发生变化。这使得UUIDv1在某些情况下可能无法保证跨设备的一致性和唯一性。
  4. 生成效率

    • UUIDv1生成过程需要访问系统时间和节点ID,可能会比其他方法(如UUIDv4)略显复杂且效率低。
  5. 替代方案的可用性

    • UUIDv4(基于随机或伪随机数生成的UUID)提供了更大的随机性和隐私保护,不需要依赖于时间或设备的标识符,因而更受欢迎。UUIDv4也避免了UUIDv1存在的许多缺点。

UUID V6 V7

为了解决UUID的一些问题, UUIDV6, UUIDV7 都尝试了进行改进, 参考文档

UUID V6

UUIDv6 相比于 UUIDv1 进行了以下改进:

  1. 时间顺序排序

    • UUIDv6 对时间戳的字节顺序进行了重新排列,使其变得可排序。UUIDv1 的时间戳是按照高位、中位和低位的顺序存储,这导致在数据库中插入时新生成的UUID可能分散在索引的随机位置,影响了数据库性能。UUIDv6 将时间戳的字节顺序调整为从高到低存储,确保相邻生成的UUID在数据库中也保持相近。
  2. 简化实现

    • UUIDv6 的设计使得现有的 UUIDv1 实现可以相对简单地调整为支持 UUIDv6,避免了完全重新设计的复杂性。
  3. 消除隐私问题

    • UUIDv1 使用 MAC 地址作为节点部分,这可能引发隐私和安全问题。虽然UUIDv6在节点部分仍然可以使用伪随机值,但在实现上可以选择避免使用MAC地址,从而降低安全风险。
  4. 改进的时钟序列处理

    • UUIDv6 保留了UUIDv1中的时钟序列,但在生成时提供了更好的保证,确保即使在同一时间戳下生成多个UUID,仍然能保持单调性和唯一性。
  5. 不再依赖于特定的时间戳格式

    • UUIDv1 使用了不太常见的100纳秒公历纪元时间戳,UUIDv6 的时间戳设计更为灵活,可以根据需要采用不同的时间戳格式。

UUIDV7

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       unix_ts_ms (48 bits)                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  ver (4 bits)  |         rand_a (12 bits)                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| var (2 bits)   |                rand_b (62 bits)                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1. 基于 Unix Epoch 时间戳
    UUIDv7 使用 Unix Epoch 时间戳(自 1970 年 1 月 1 日以来的毫秒数)作为时间源。这种时间戳更为常见和易于理解,而 UUIDv1 使用的是不常见的 Gregorian 时间戳(以 100 纳秒为单位的计时),这使得其在处理和表示上更加复杂。
  2. 排序性
    UUIDv7 设计为时间有序,可以直接按字节比较进行排序。由于它的时间戳是以毫秒为单位的,因此在数据库索引中的插入顺序更为合理,可以提高插入性能,而 UUIDv1 和 UUIDv6 的时间戳分散在不同的字段中,导致在数据库中插入时索引局部性较差。
  3. 改进的熵特性
    UUIDv7 提供了更好的熵特性,使用了额外的随机数位(rand_a 和 rand_b)来增加唯一性。这使得 UUIDv7 在高并发情况下生成的 UUID 更加独特,降低了碰撞的可能性。
  4. 简化的结构
    UUIDv7 的结构比 UUIDv1 和 UUIDv6 更加简单,专注于提供易于实现的时间戳和随机数据的组合。UUIDv7 包含一个48位的 Unix 时间戳,后面跟着一部分版本和随机数据,整体结构更加清晰。
  5. 去除了 MAC 地址
    UUIDv1 包含了设备的 MAC 地址,这在隐私和安全性上带来了风险。UUIDv7 不再使用 MAC 地址,改为完全依赖随机数生成器和时间戳,从而提高了安全性。

可以看到UUIDV7的结构已经具有了相当的时间内聚性, 即在一段时间内, UUID的大小总是在某个范围内, 这其实已经满足了我们对于主键的要求. 而且一共74bit的随机位也保证了非常好的随机性.

在增加上主键的唯一性保证, 其实已经基本满足了我们对于主键的要求.

标签:UUID,UUIDv1,UUIDV7,生成,时间,做主,UUIDv6,bits
From: https://www.cnblogs.com/pDJJq/p/18393122/uuidv7-i-just-want-to-use-uuid-as-the-main-key-1v

相关文章

  • 雪花算法和UUID
    雪花算法和UUIDUUIDUUID是一种唯一且不需要中央协调的ID,它使用某种规则创建ID,而不是某种中心化的自增方式,使得其成为创建成本最低的ID类型。到目前为止UUID一共有5个实现版本版本1:按照UUID定义的每个字段的意义来实现,使用的变量因子是时间戳+时钟序列+节点信息(Mac地址),考的......
  • java.util.UUID
    概述Aclassthatrepresentsanimmutableuniversallyuniqueidentifier(UUID).一个不可变的通用的唯一标识符的classAUUIDrepresentsa128-bitvalue.一个uuid代表一个128位的值 UUID的版本UUID有多个版本,每个版本有不同的生成方式。常用的......
  • Android开发 - UUID 类通用唯一标识符解析
    什么是UUIDUUID类是一个非常有用的工具,用来生成和处理通用唯一标识符(UUID)。UUID是一种标准的标识符,用于在计算机系统中唯一标识信息(UniversallyUniqueIdentifier)的缩写。它的目的是确保在不同的系统、不同的时间和地点生成的标识符是唯一的。UUID通常用于数据库记录、会话......
  • @clickhouse/client-web部署后出现ClickHose query error:crypto.randomUUID is not a
    crypto.randomUUID报错我这里是因为使用使用@clickhouse/client-web组件,在服务器部署后在浏览器访问界面导致的crypto.randomUUIDisnotafunction报错如果你用http://localhost:端口,在服务器浏览器上访问这个部署的页面,发现不会报错,这是因为,你使用localhost访问......
  • iOS开发基础149-由UUIDString引发的思考
    问题1:[[UIDevicecurrentDevice]identifierForVendor].UUIDString什么情况下值会变化?[[UIDevicecurrentDevice]identifierForVendor].UUIDString是一个用于标识设备的唯一标识符(UUID),针对同一应用程序供应商(即同一开发者的应用程序集合),在设备上不变。然而,有一些情况会导致这个......
  • Go 语言 UUID 库 google/uuid 源码解析:UUID version7 的实现
    google/uuid库地址建议阅读内容在阅读此篇文章之前,建议先了解UUIDv1的构成、UUIDv4的API以及掌握位运算。了解UUIDv1的构成可以参考Go语言UUID库google/uuid源码解析:UUIDversion1的实现或RFC9562。了解UUIDv4的API可以看Go语言UUID库google......
  • Go 语言 UUID 库 google/uuid 源码解析:UUID version4 的实现
    google/uuid库地址本文将解析googl/uuid库中UUID变体10版本4的实现。版本4的UUID采取完全随机的方式实现,简单来说就是将UUID中的122位全部随机填充(剩余的6位作标记位)。版本4的UUID存在一定的重复风险,但就如源码注释中所说:“一年内创建几十万亿个UUI......
  • 【WCH蓝牙系列芯片】-CH9141模块AT指令增加自定义透传UUID服务
    -------------------------------------------------------------------------------------------------------------------------------------在使用沁恒的蓝牙串口透传芯片CH9141,这是一个自带固件,拿来接上串口就可以直接用的蓝牙模块芯片。支持串口AT配置和在从机模式下......
  • 前端取唯一标识 UUID
    //使用工具fingerprintjs可以简单取到UUID1<!DOCTYPEhtml>2<htmllang="en">34<head>5<metacharset="UTF-8">6<metahttp-equiv="X-UA-Compatible"content="IE=edge">7<m......
  • 什么是跨域请求未在攻击?浏览器在这方面做了哪些努力? 为什么随机UUID做token 可以解
    跨域请求伪造攻击(Cross-SiteRequestForgery,简称CSRF)是一种恶意攻击,其中攻击者诱使用户在已认证的会话中执行未授权的操作。通过在受害者访问的站点中嵌入恶意请求,攻击者可以利用用户的身份来执行一些用户未授权的操作,如转账、修改资料等。跨域请求伪造攻击(CSRF)攻击原理用户......