📝 博客 · 2026-07-29 · ⏱ 9 分钟

什么是UUID?什么时候用?

讲清楚 UUID 是什么、5 个版本的区别、碰撞概率有多低,以及和自增 ID 的选择。

一、UUID 是什么

UUID(Universally Unique Identifier,通用唯一识别码)是一个 128 位的数字,通常表示成 32 个十六进制字符,用连字符分成 5 段:

550e8400-e29b-41d4-a716-446655440000

格式是 8-4-4-4-12,共 36 个字符(含 4 个连字符)。这个格式几乎在所有系统里都是统一的——无论是 Windows 的 GUID、Java 的 UUID、还是 PostgreSQL 的 uuid 类型,长得都一样。

UUID 的目标是:在分布式系统中,不需要中心协调,也能保证生成的 ID 不重复。这一点非常关键,后面会详细讲。

二、UUID 的 5 个版本

UUID 规范(RFC 4122)定义了 5 个版本,每个版本的生成方式不同:

版本生成方式特点典型场景
v1时间戳 + MAC 地址时间有序,会暴露机器 MAC几乎不用
v2DCE Security 版本很少实现基本不用
v3命名 + MD5 哈希同输入同输出,可重现历史遗留
v4随机数最常用,完全随机默认选择
v5命名 + SHA1 哈希同输入同输出,比 v3 更安全命名场景

v1:基于时间

用当前时间戳(纳秒级)+ 机器 MAC 地址生成。优点是时间有序,按 UUID 排序约等于按时间排序。缺点是会暴露机器的 MAC 地址,有隐私问题,而且同一台机器同一瞬间并发生成可能冲突。

v3 和 v5:基于命名

给定一个"命名空间 UUID"和一个"名字字符串",哈希一下得到 UUID。同样的输入永远产生同样的输出,适合"需要可重现"的场景。v3 用 MD5,v5 用 SHA1,现在推荐用 v5。

v4:基于随机数

最常用的版本。128 位里有 122 位是随机数(剩下 6 位是版本和变体标识),完全靠随机性保证唯一性。绝大多数语言的默认 uuid() 函数生成的就是 v4。

生成 v4 的 JavaScript 示例:

function uuidv4() {
  return crypto.randomUUID();
}

console.log(uuidv4());
// "1b9e6f7a-3c4d-4e5f-8a2b-9c1d2e3f4a5b"

浏览器和 Node.js 都内置了 crypto.randomUUID(),直接调用即可。

三、为什么 v4 最常用

v4 之所以成为事实标准,原因有三:

  1. 简单:不需要时间戳、不需要 MAC 地址、不需要命名空间,只要随机数
  2. 安全:不暴露机器信息,不依赖网络
  3. 无状态:每次调用互相独立,没有时序依赖

但 v4 也有缺点:完全无序。这一点对数据库性能有影响,后面会展开讲。

四、碰撞概率有多低

v4 UUID 有 122 位随机性,可能的取值数量是 2^122,约等于 5.3 × 10^36。这个数字大到难以想象。

根据生日悖论计算:

生成数量碰撞概率
103 万亿个50%
1 亿个约百万分之一
100 万个约十亿分之一
100 个几乎为 0

换种说法:如果你每秒生成 10 亿个 UUID,连续生成 85 年,碰撞概率仍然小到可以忽略

所以在工程实践中,UUID 碰撞几乎不需要担心。即使发生了,也极可能是随机数生成器本身有 bug,而不是 UUID 算法的问题。

五、UUID vs 自增 ID

这是数据库设计里最经典的争论之一。我们来对比一下。

自增 ID

1, 2, 3, 4, 5, ...

优点:

缺点:

UUID

550e8400-e29b-41d4-a716-446655440000

优点:

缺点:

对比表

维度自增 IDUUID(v4)
长度8 字节16 字节
全局唯一
客户端生成
索引性能好(有序)较差(随机)
可猜测性几乎不可猜测
分库分表复杂天然支持
对人友好

六、什么时候该用 UUID

根据上面的对比,可以总结出几个清晰的判断标准。

推荐用 UUID 的场景

  1. 分布式系统:多个服务、多个数据库同时写入,不能用自增
  2. 客户端先生成 ID:比如离线 App 创建记录,联网后再同步
  3. 需要不可猜测:比如邀请链接 ?token=xxxx-xxxx
  4. 数据需要合并:多个库的数据汇到一起,自增 ID 会冲突

推荐用自增 ID 的场景

  1. 单库单表:业务简单,没有分布式需求
  2. 对性能敏感:高并发写入场景
  3. 对外不暴露 ID:用业务字段(用户名、slug)对外展示

折中方案:UUID v7

为了解决 v4 无序导致数据库性能下降的问题,近年出现了 UUID v7(还在标准化中)。它把前 48 位用作时间戳,后面是随机数:

017f22e2-79b0-7cc3-98c4-dcfe0e23ce1d

这样既保留了 UUID 的全局唯一性,又有时间顺序,数据库写入性能和自增 ID 接近。未来几年 v7 很可能成为默认选择。

七、UUID 的常见使用场景

场景说明
数据库主键尤其是分布式数据库(Cassandra、MongoDB)
API 请求追踪每个请求分配一个 UUID,日志全链路串联
文件名用户上传文件时用 UUID 命名,避免重名
设备标识App 首次启动生成 UUID 作为设备 ID
会话 token登录后生成 UUID 作为 session token
事件 ID消息队列、事件溯源里每个事件的唯一 ID
测试数据自动化测试里生成假数据的主键

八、UUID 的存储建议

在数据库里存 UUID 时,有几种常见做法:

存储方式体积查询性能说明
字符串(36 字符)36 字节较差可读但体积大,不推荐
字符串(无连字符)32 字节较差略好,但仍大于二进制
BINARY(16)16 字节MySQL 推荐
uuid 类型16 字节PostgreSQL 原生支持

建议:除非有特殊需求,数据库里 UUID 应该用 16 字节的二进制存储,而不是 36 字符的字符串。两者体积差一倍多,索引和查询性能差距也很大。

九、实践推荐

日常开发中经常需要生成 UUID——做测试数据、生成临时 token、给文件命名等等。手写代码虽然不复杂,但用在线工具更直观,还能一次生成多个:

支持 v1、v4、v5 多版本,批量生成,一键复制,还可以选择带不带连字符的格式,是开发调试和测试数据准备时的常用工具。