UUID v1 v4 v7 怎么选?数据库主键用哪个?
UUID 数据库 后端
UUID v1 v4 v7 怎么选?数据库主键用哪个?
每个项目都要选 UUID 版本。v1 太老、v4 太随机、v7 太新。这篇给出三种版本的对比和场景化推荐。
想直接生成?打开 RuMystic UUID 生成器 — 支持 v1 v4 v7,批量生成,本地运行。
三个版本的核心区别
| 版本 | 生成方式 | 可排序 | 随机性 | 适用场景 |
| v1 | 时间戳 + MAC 地址 | 是(按时间) | 低 | 老系统兼容 |
| v4 | 全随机 | 否 | 高 | 通用默认 |
| v7 | 毫秒时间戳 + 随机 | 是 | 中 | 数据库主键 |
UUID v1:时间 + MAC
结构:60 位时间戳(100 纳秒精度,从 1582-10-15 起算)+ 48 位 MAC 地址 + 14 位时钟序列。
优点:
- 可排序(按生成时间)
- 不需要协调,每台机器独立生成
- 泄漏生成机器的 MAC 地址(隐私问题)
- 不同机器时钟不同步可能重复
- 时间戳起算点是 1582 年(格里高利历改革),不直观
- RFC 9562(2024)已把它标记为「不推荐新系统使用」
UUID v4:全随机
结构:122 位随机数 + 4 位版本号 + 2 位变体号。
优点:
- 实现简单,
crypto.randomUUID()一行搞定 - 碰撞概率极低(2.71 × 10¹⁸ 个才有 50% 碰撞)
- 不泄漏任何信息
- 不可排序 — 生成时间相近的两个 v4 完全无序
- 数据库 B-tree 索引碎片化严重(随机插入)
- 索引膨胀,写入性能随表增长下降
- 临时令牌(密码重置、分享链接)
- 不存数据库的 ID(前端临时 ID)
- 不需要按时间排序的场景
UUID v7:时间排序 + 随机
结构(RFC 9562,2024 年标准):
- 48 位 Unix 毫秒时间戳(前面)
- 12 位随机数
- 62 位随机数 + 变体
- 可排序 — 字典序 = 时间序,B-tree 索引顺序插入
- 数据库索引不碎片化,写入快 1.5-3 倍
- 日志关联、事件溯源、对象存储 key 天然有序
- 不泄漏 MAC 地址
- 生成时间可推断(泄漏创建时间,类似
created_at字段) - 同一毫秒内大量并发写入可能集中在 B-tree 最后一页(罕见,需要 10 万+ TPS 才显现)
- 较新,部分老系统/库不支持
- 数据库主键(最推荐)
- 事件溯源的 event ID
- 日志的 trace ID
- 对象存储的 key(按时间排序扫描快)
数据库性能对比
在 Postgres 插入 1 亿行,主键分别为 v4 和 v7:
| 指标 | v4 | v7 |
| 插入耗时 | 100% | 50-70% |
| 索引大小 | 100% | 60-80% |
| 缓存命中率 | 较低 | 较高 |
| 范围扫描(按时间) | 慢(需扫全表) | 快(物理连续) |
原因:v4 随机插入触发 B-tree 页分裂,v7 顺序追加到最后一页,几乎不分裂。
安全性考虑
v1 的隐私问题
v1 UUID 包含 MAC 地址。早期 WordPress 用 v1 UUID 做评论 ID,结果泄漏了服务器 MAC 地址。现在新系统都不该用 v1。
v4 的不可预测性
v4 完全随机,适合做 capability token(URL 里的不可猜测 ID)。
v7 的时间泄漏
v7 暴露生成时间。如果你的 ID 用在 URL 里,且「这个对象什么时候创建」是敏感信息(比如用户注册时间),不要直接用 v7。可以:
- 用 v7 做内部主键,对外用 v4 做公开 ID
- 或者 hash v7 后再暴露
各语言支持(2026 年)
| 语言 | v1 | v4 | v7 |
| JavaScript | uuid 包 | crypto.randomUUID() | uuid v11+ |
| Python | uuid.uuid1() | uuid.uuid4() | uuid.uuid7() (3.13+) 或 uuid_utils |
| Go | google/uuid | google/uuid | google/uuid v1.6+ |
| Java | UUID | UUID.randomUUID() | uuid-creator 库 |
| .NET | Guid | Guid.NewGuid() | Guid.CreateVersion7() (.NET 9+) |
| Postgres | uuid-ossp | gen_random_uuid() | pgcrypto 1.5+ 或应用层生成 |
选择决策树
你的 UUID 会作为数据库主键吗?
├─ 是 → 用 v7(顺序插入,索引不碎片)
└─ 否 → 你的 UUID 会出现在 URL 里且需要不可猜测吗?
├─ 是 → 用 v4(完全随机,适合做 token)
└─ 否 → 你需要按时间排序吗?
├─ 是 → 用 v7
└─ 否 → 用 v4(最通用,所有库都支持)
实战建议
新项目
数据库主键一律 v7。前端展示用 v7 没问题(除非创建时间敏感)。临时 token 用 v4。
老项目迁移
不要把已有 v4 主键改成 v7 — 索引会乱。新表用 v7,老表保持 v4。
分布式系统
v7 不需要协调,每台机器独立生成。同一毫秒内的碰撞概率(2.4 × 10¹¹ 才有 50% 碰撞)可以忽略。
事件溯源 / 日志
v7 是最佳选择。trace ID 用 v7,按时间排序天然成立,不用额外加 timestamp 字段做复合索引。
生成测试
想看三种 UUID 长什么样?打开 RuMystic UUID 生成器,选版本、设数量、一键生成。
v1: 6b1d1a20-0822-11f1-8a3c-0242ac130003
v4: 4f7c8a92-3b1e-4d5f-9a2c-8e1f0b3a4c5d
v7: 0196398a-7c4e-7d2b-a3f1-4c8e1b2a3d5e
注意 v7 开头 0196398a 是 Unix 毫秒时间戳的十六进制,2026 年的开头大概是 019 开头。
总结
- v1 — 别用,老古董
- v4 — 通用默认,做 token / 临时 ID
- v7 — 数据库主键、日志、事件溯源首选