简体中文

开发者工具 · UUID 生成器

从 128 位到 36 字符:UUID 文本编码的工作原理

· 工作原理

uuid 密码学 浏览器 API

一个 128 位值显示为字节,然后显示为带连字符的 36 字符十六进制,然后显示为 22 字符 base64url,说明了空间权衡
原始 ToolAcre 矢量图

UUID 是 16 字节,但其熟悉的形式是 36 个字符。这篇文章解释了十六进制加倍、连字符、大小写规则以及人们在标准形式太长时使用的较短编码。

为什么列比值宽 - 16 字节值在文本中花费 36 个字符,以及这对 URL 和存储意味着什么

当您选择 UUID 格式时,存储列宽度会急剧增加。 128 位值是 16 字节,但其文本表示形式取决于编码:十六进制(36 带连字符的字符,32 不带连字符)、base64url(22 字符)、base58(22–23 字符)、Crockford base32(26 字符)。如果您的架构将 UUID 存储为 VARCHAR(36),则您将在每行中花费 36 个字符。在具有 1 十亿行且没有其他列的表中,与 16 GB 的二进制文件相比,这是 36 GB 的文本开销。这种选择不仅仅是装饰性的,而且是实用性的。它会影响查询大小、网络往返和缓存压力。规范格式为 36 个字符:八个十六进制数字、连字符、四个十六进制数字、连字符、四个十六进制数字、连字符、四个十六进制数字、连字符、十二个十六进制数字。

十六进制将所有内容加倍 - 每个字节变成两个字符,四个连字符完成 36

每个字节恰好变成两个十六进制字符(0–9,a–f)。出于可读性和首次指定 UUID 时遗留的原因,使用连字符。十六进制编码使字节数加倍:16 字节变为 32 十六进制数字加上 4 连字符。它是最慢的编码,也是最长的编码,但是人类可读并且到处都受支持。大小写规则:RFC 9562 要求规范输出使用小写字母,但输入不区分大小写。存储大写字母会浪费标准化的机会,因此存储小写字母并在输入时不区分大小写进行比较。 Base64url 编码使用 64 字符字母表(A–Z、a–z、0–9、减号、下划线)将三个字节表示为四个字符。十六个字节变为 21 个字符加上 1 个填充字符,总共 22 个字符。 Base64url 删除 URL 中保留的填充和标准字符(加号和斜杠)。

大小写规则 - 输出小写,输入不区分大小写,以及为什么混合大小写比较会导致无提示不匹配

与十六进制相比,base64url 格式的 UUID 可以保存 14 个字符,并且在没有百分比编码的 URL 中有效。缺点是可读性较差(小写字母看起来像数字;b、8、B 和 8 很容易混淆)。 Base58 由比特币和其他区块链使用,并删除不明确的字符(0、O、I、l),使结果为 22–23 字符,同时保持可读性。 Crockford base32(专为类似于 ISBN 的校验和格式而设计)使用 26 字符,并优先考虑正确性而不是简洁性。 Microsoft GUID 字节顺序陷阱适用于某些数据库中的 UUID 存储。 RFC 9562 指定所有字节的网络字节顺序(大端)。某些 Microsoft SQL Server 配置在前三个字段中存储具有小端字节顺序的 GUID。

较短的编码 — 22 字符处的 base64url、base58 和 Crockford base32,在可读性和复制粘贴安全性方面进行权衡

存储在大端和小端中的相同 128 位值会生成不同的十六进制字符串。存储为 Microsoft GUID 的 UUID 550e8400-e29b-41d4-a716-446655440000 可能会被检索为 00840e55-9be2-d441-a716-446655440000 (字节 0–3 和4–5 和 6–7 颠倒)。如果您的系统在符合 RFC 的系统和 Microsoft 系统之间建立桥梁,您必须意识到这一点,并在边界处进行规范化或记录您在每列中使用的格式。工作示例:十六进制的 v4 UUID 9b2e4f1a-4f3e-4c1a-8a7d-1b2c3d4e5f60 占用 36 个字符。作为 16 字节,它是 9b 2e 4f 1a 4f 3e 4c 1a 8a 7d 1b 2c 3d 4e 5f 60。在base64url中:分割成三字节块,转换为base64,剥离填充:my5PGk8-TBqKfRssPTRPX2A。不带连字符的十六进制:9b2e4f1a4f3e4c1a8a7d1b2c3d4e5f60(32 字符)。

Microsoft 字节顺序陷阱 — GUID 的前三个字段如何以小端存储,因此相同的字节可以打印为两个不同的字符串

Base64url 保存 14 个字符; base58 会保存大致相同的内容;十六进制是标准。根据您的用例进行选择:如果标识符出现在 URL 中并且每个字符都很重要,请使用 base64url;如果它出现在人类阅读的日志和 UI 中,请使用十六进制规范形式;如果您正在构建校验和很重要的区块链系统或分布式系统,请使用 base58 或 Crockford base32。选择列类型时,请存储针对您的实际访问模式进行优化的值。如果您频繁查询 UUID 并需要不区分大小写的匹配,请存储二进制 (16) 并让数据库处理表示形式。如果按子字符串查询(搜索以前缀开头的 UUID),则十六进制在调试输出中更具可读性。

工作示例 — 一个以字节、规范十六进制和缩写形式编写的标识符,显示每个转换步骤

如果导出到 CSV 并通过电子邮件发送给非技术用户,则十六进制更容易识别。如果您空间有限(具有本地缓存​​的移动应用程序),base64url 或 base58 可以节省带宽。 ToolAcre 生成器输出规范的 36 字符十六进制格式;如果您需要不同的编码,格式正确的检查仍然有效,因为它会在检查格式之前规范化任何有效的表示形式。在编码或解码数百万个 UUID 时,性能考虑因素很重要。十六进制编码很简单:每个字节在 O(1) 时间内将每个字节转换为两个字符。解码同样简单。 Base64 编码和解码使用查找表,速度稍慢(大致比每字节十六进制慢 2–3 倍,具体取决于硬件和实现)。 Base58 的速度要慢得多,因为它本质上是基数转换并且需要模运算。

这不包括什么 — 数据库列选择,例如本机 uuid 类型与二进制 (16),单独介绍

如果您的系统在热循环中对 UUID 进行编码或解码(高频标识符生成、批量导出),则十六进制速度更快。如果编码很少发生并且 14 字符节省很重要,则 base64url 是一个合理的权衡。 ToolAcre 生成器输出十六进制,因此您可以在不牺牲兼容性的情况下获得性能优势。字符串比较语义因编码而异。十六进制 UUID 可以作为字符串进行比较: 550e8400-e29b-41d4-a716-446655440000 < 550e8400-e29b-41d4-a716-446655440001 (字典比较有效)。二进制 UUID 可以按字节进行比较:逐字节比较与数字比较相同。但是,Base64url 和 base58 编码的 UUID 在字典字符串比较中不保留数字顺序。如果您的系统依赖于 UUID 的字典排序(构建索引或数据库键的一种令人惊讶的常见模式),则必须使用十六进制、二进制或可排序的 UUID 变体(v6 或 v7)。

要点:在边界处保持规范形式 — ToolAcre 生成器输出标准 36 字符 UUID,并且其检查接受该形式的字符串

ToolAcre 生成器当前生成 v4 UUID,无法按编码顺序排序。互操作性需要对单一编码进行标准化。同时接受十六进制、base64 和 base58 UUID 的系统必须在处理之前将所有输入标准化为规范形式。这是可能的,但增加了复杂性。外部 API 或数据库可能需要特定的编码:一些 API 期望 urn:uuid: 带前缀的十六进制,其他 API 期望无连字符的十六进制,还有一些 API 期望 base64url。在 API 合约中清楚地记录您系统的 UUID 编码期望。 ToolAcre 生成器始终输出规范的十六进制;如果您需要其他编码,请明确执行转换并向团队记录权衡(空间、性能、可读性、可排序性)。