03 / 指南
UUID vs ULID:为你的应用选择标识符
UUID v4 对 v7、ULID 的结构与可排序性、随机标识符对 B 树索引的影响、碰撞概率、在 URL 中的暴露,以及如何本地生成标识符。
应用标识符必须做到什么
生成的标识符只有一份本职工作——唯一——外加几份顺手接下的活:无需协调即可在任何地方生成、存储紧凑、排序可预期、不泄露任何难堪的信息。UUID 与 ULID 都过了唯一性这一关;分歧在那之后的一切。
- 无需协调去中心化生成:任何服务、工作线程或浏览器标签页都能铸造标识符,无需请示中央计数器,这正是两种格式都适合分布式系统的原因。
- 同为 128 位都是 128 位:UUID 是写成 36 个带连字符十六进制字符的 128 位值;ULID 把同样的 128 位装进 26 个 base32 字符。
- 布局才是关键真正的问题是布局:哪些位随机、哪些位编码时间,决定了标识符在索引里的行为以及它会泄露什么。
UUID 版本:v4 随机,v7 按时间排序
RFC 9562 定义了几个 UUID 版本,但应用开发里只有两个占主导。第 4 版用随机数填满 128 位中的 122 位,不嵌入任何其他信息;第 7 版以 48 位 Unix 毫秒时间戳开头,剩余 74 位填随机数。
- v4:纯随机v4 是隐私最大化的选择:值本身不透露生成的时间和地点,122 个随机位提供的唯一性任何应用都用不完。
- v7:时间在前v7 按创建时间排序,精确到毫秒,后生成的标识符排在前者之后——这正是数据库希望主键具备的性质。
- 跳过 v1旧版本属于历史:v1 嵌入 MAC 地址和时钟值,两者都会泄露;v3 与 v5 是基于名字的哈希,用于推导稳定 ID,不是新鲜随机数。
ULID:文本形态也可排序且紧凑
一个 ULID 是 26 个 Crockford base32 字符:前 10 个字符编码 48 位毫秒时间戳,其余 16 个编码 80 个随机位。字母表刻意排除 I、L、O、U,因此标识符经得起口头朗读和照截图手敲。
- 字符串排序即时间排序字典序即时间序:把 ULID 当普通字符串排序,就按创建时间排好了,无需解析——在日志行、文件名和键值存储里都好用。
- 26 个安全字符紧凑且 URL 安全:26 个不区分大小写的字符,没有连字符和符号,比 UUID 的 36 个字符短,放进任何路径段或查询参数都安全。
- 毫秒内单调同一毫秒内,次序来自随机部分;像 Toolars 批量生成器那样单调递增它的生成器,连同毫秒的标识符也能保持生成顺序。
随机 ID 会让索引碎片化
B 树索引是有序的,插入一个随机 UUID v4 每次都会写到随机的叶子页:页分裂、缓冲池颠簸、索引被空洞撑大。按时间排序的标识符追加在索引右缘附近,把插入变成 B 树的最佳情形。
这就是为什么这个选择属于模式设计阶段,而不是等第一个变慢的季度之后:迁移主键意味着重写每一行以及引用它的每个外键。表会一直很小,v4 的无序永远不会显形;表会在持续写入下长到数亿行,有序格式从第一天起就在回报你。
- 随机即离散用 v4 做主键时,写入密集的表会出现更多页分裂、更低的填充率,以及与同尺寸有序键相比明显更差的写入吞吐。
- 有序即追加v7 与 ULID 在保持去中心化生成的同时恢复局部性——没有序列、没有协调,也仍然无法预测其他行的 ID。
- 权衡要实测代价真实但有限:128 位是 bigint 存储的两倍;按时间排序的键会把当天的写入集中在索引右缘,这只在极高插入速率下才有影响。
碰撞、URL,以及 ID 会透露什么
先算碰撞:v4 有 122 个随机位,生成十亿个标识符的碰撞概率约为 10 的 18 次方分之一——实际上永远不会。ULID 的 80 个随机位守护的是另一份预算:同一毫秒内创建的标识符。
把任何可疑的值粘进校验器:它识别带 RFC 9562 变体与版本半字节的 36 字符标准 UUID 形态、带溢出规则的 26 字符 ULID 字母表,并为按时间排序的格式报告嵌入的时间戳——日志里的一个值,在你基于它构建之前就能告诉你它是什么。
- 概率可以忽略两种格式都不是安全边界:URL 里的标识符用于寻址没问题,但任何看到它的人都能引用它——授权必须来自访问检查,而不是 ID 的不透明。
- ID 不是机密v7 与 ULID 按设计泄露创建时间;校验器会公开地把它解析出来。这通常是无害的元数据,但对公开对象要有意识地做这个决定。
- 时间可见自增数据库 ID 会泄露体量与增长速度;随机和时间加随机的标识符不透露记录数量的任何信息。
不经过服务器地生成与校验
生成标识符只需要一种稀缺资源——好的随机性——而浏览器本来就有。工作区从 crypto.getRandomValues 取随机数,整个批次都在标签页内生成,从不传输任何值。
- 每批 1–100 个选择 UUID v4、UUID v7 或 ULID,每批生成 1 到 100 个;v7 与 ULID 批次会单调递增随机字段,整批都保持生成顺序。
- 大小写与导出输出大小写只是展示选择:规范形、大写或小写,支持一键复制全部,以及换行文本和 CSV 下载,CSV 会记录每个标识符的嵌入时间。
- 即时校验校验即时回答结构问题:长度、字母表、UUID 版本与变体、nil 与 max 特殊值、ULID 溢出,以及 UTC 的嵌入时间戳。
ULID 是 base32;你的令牌多半是 Base64。
字节到文本的编码藏在每个标识符与令牌之下——弄清它们的代价,以及在哪里值得用。