三个常用版本对比
| 版本 | 组成 | 特点 | 适用 |
|---|---|---|---|
| v1 | 时间戳 + 节点(MAC) | 大致有序,但泄漏时间与设备信息 | 内部、需顺序追踪的历史系统 |
| v4 | 122 位随机 | 最常用,无顺序 | 通用唯一标识 |
| v7 | 时间戳前缀 + 随机 | 可按时间排序,索引友好 | 数据库主键、日志 ID |
碰撞概率有多大
v4 需要生成大约 2.7×10¹⁸ 个UUID 才有 50% 概率出现一次碰撞。真实业务规模下“重复”几乎不是问题,真正的痛点是无序。
做主键的性能陷阱
随机 UUID 会让 B+ 树索引随机插入,带来页分裂与写放大;数据量增长后,插入性能和缓存命中率都会下降。解决办法是让 ID 保持时间局部性:用 v7 / ULID,或用数据库自增、雪花 ID。已有大量 v4 主键的系统,也可以保留 UUID 作对外标识、内部另设顺序主键。
三个不该用 UUID 的场景
- 需要短、能口头传播的标识:邀请码、短链用 UUID 太长,换成更短的编码(如 Base62 随机串);
- 需要人工识别与排错:订单号这类用有语义的规则更好读;
- 当作安全令牌:见下。
ID 方案怎么选
| 方案 | 有序性 | 长度 | 适用 |
|---|---|---|---|
| 数据库自增 | 天然有序 | 小 | 单库、内部系统 |
| 雪花 ID | 时间有序 | 64 位整数 | 分布式、需紧凑 ID |
| UUID v4 | 无序 | 36 字符 | 通用唯一标识、对外暴露 |
| UUID v7 / ULID | 时间有序 | 36 / 26 字符 | 数据库主键、日志追踪 |
生成与使用建议
- 用系统或标准库生成(
crypto.randomUUID()、各语言 uuid 库),别用Math.random()拼,它不是密码学安全的; - 存储用 16 字节二进制或去连字符的 32 字符形式,比 36 字符字符串更省空间、比较更快;
- 需要按时间查询就让 ID 自带时间序(v7 / ULID),否则额外加一列创建时间并建索引;
- 对外暴露前评估信息泄漏:v1 带时间与 MAC,v7 带创建时间,v4 不带任何结构信息。
几个常被问到的问题
UUID 能当令牌吗?不能。v4 只有 122 位随机,且没有有效期、作用域与撤销语义;令牌应用 256 位随机串结合服务端校验。UUID 会泄漏信息吗?v1 泄漏生成时间与设备 MAC,v7 泄漏创建时间(通常可接受),v4 不泄漏任何结构信息。ULID 和 v7 选哪个?都能按时间排序:ULID 更短(26 字符),v7 是标准 UUID 格式(36 字符),按团队习惯选。
动手试试:UUID 生成