一、格式:8-4-4-4-12
标准写法是 36 个字符(32 个十六进制 + 4 个连字符):
550e8400-e29b-41d4-a716-446655440000
第 13 位(第三段首字符)是版本号,第 17 位是变体标识。所以看到 -41d4- 就知道是 v4,看到 -71d4- 就是 v7。
二、各版本的区别
| 版本 | 生成依据 | 特点 |
|---|---|---|
| v1 | 时间戳 + 时钟序列 + MAC 地址 | 可排序,但泄露 MAC 和生成时间,隐私差 |
| v3 | MD5(命名空间 + 名称) | 同样输入永远同样输出,可复现 |
| v4 | 122 位随机数 | 最常用,无信息泄露,完全无序 |
| v5 | SHA-1(命名空间 + 名称) | 同 v3 但用 SHA-1,更推荐 |
| v7 | 48 位毫秒时间戳 + 随机 | 按时间有序,适合做数据库主键 |
v3/v5 的价值在于「确定性」:比如给「用户邮箱」生成固定 ID,同一邮箱在任何系统都得到同一个 UUID,适合做数据去重与跨系统映射。
三、碰撞概率有多低
v4 有 122 位随机位,总空间约 5.3×10³⁶。按生日问题估算,要生成约 2.7×10¹⁸ 个 UUID 才有 50% 概率出现一次碰撞。每秒生成 10 亿个,也要 80 多年。所以业务上可以认为「不会重复」,不需要先查库再插入。
但要注意:用弱随机源生成的「伪 UUID」不算。自己用 Math.random() 拼字符串,碰撞概率会高得多,必须用 crypto.randomUUID()、uuid 库或数据库的 gen_random_uuid()。
四、做主键的真实代价
UUID 是字符串(36 字节)或 16 字节二进制,比自增 BIGINT(8 字节)大。更关键的是顺序:
- v4 完全随机 → 每次插入都落在 B+ 树中间,导致页分裂、缓存命中率下降,写入量大时性能明显变差。
- v7 / ULID / 雪花 ID → 高位是时间,近似单调递增,插入集中在末尾,性能和自增 ID 接近。
所以如果要「分布式唯一 + 好索引」,优先 v7 或雪花 ID;如果只是要个不重复的对外标识,数据库内部仍用自增主键、外部加一列 UUID 做映射,是最稳的组合。
五、使用建议
- 对外暴露的 ID 用 UUID,避免自增 ID 被遍历(
/order/1、/order/2的问题)。 - 数据库主键 优先
BIGINT自增或雪花;非要用 UUID 就存成 16 字节BINARY(16)而不是 36 字符CHAR(36)。 - 不要从 UUID 里解析时间(v1/v7 除外),v4 里没有信息。
- 大小写:十六进制大小写都合法,入库前统一小写,避免同一 ID 出现两种形式。
- 去掉连字符:存储时去掉
-可省 4 字节,展示时再格式化回来。
需要批量生成测试数据时,用 UUID 生成器;要生成随机密码或验证码,用 随机生成器。
小结
v4 随机、最常用;v5 可复现;v7 时间有序、适合主键;碰撞概率可忽略但必须用密码学随机源;做主键要注意随机性带来的索引代价。