🆔 UUID 使用指南:自增 ID 还是 UUID?开发者该如何选择

作者:kaenfsk · 发布于 2026 年 8 月 · 阅读约 8 分钟 · 最后复核 2026 年 10 月 12 日 · 内容与维护标准

什么是 UUID

UUID(Universally Unique Identifier,通用唯一标识符)是一个 128 位(16 字节)的标识符标准,由国际标准化组织在 ISO/IEC 11578 中定义。它由 32 个十六进制数字组成,通常以 8-4-4-4-12 的形式用连字符分组显示:550e8400-e29b-41d4-a716-446655440000。

UUID 的核心价值在于"全球唯一":只要按照规范生成,任何人在任何时间、任何设备上生成的 UUID 几乎不可能重复。这意味着你不需要一个中心服务器来分配 ID,分布式系统中的每个节点都可以独立生成唯一标识。

UUID 的主要版本

  • v1(基于时间) — 由时间戳、时钟序列和节点 MAC 地址生成,包含生成时间和设备信息,可追踪性带来隐私风险
  • v4(基于随机数) — 完全由随机数生成(122 位随机),不包含任何时间或设备信息,隐私性最好,是目前最常用的版本
  • v7(基于时间排序) — 结合时间戳与随机数,既能保证唯一性,又具有时间排序特性,对数据库索引友好,是新兴推荐方案

在大多数现代场景中,UUID v4 是最稳妥的选择:无需依赖硬件信息,隐私安全,生成简单。如果你的数据量很大且对索引性能敏感,可以关注 v7。

自增 ID 与 UUID 对比

维度自增 IDUUID
唯一性仅在单库内唯一全球唯一
生成方式依赖数据库自增客户端可独立生成
信息泄露可推测业务量不可推测
存储占用4-8 字节16 字节
索引性能顺序插入,性能好随机插入,可能页分裂
分布式支持需全局协调天然支持

如何选择

优先使用 UUID 的场景

  • 分布式系统、微服务架构,需要多节点独立生成 ID
  • 数据需要跨库合并、迁移或同步
  • ID 暴露在 URL 或 API 中,不希望被枚举探测
  • 客户端需要预先生成 ID(如离线场景)

优先使用自增 ID 的场景

  • 单机小型应用,数据量不大,无合并需求
  • 对存储空间和索引性能要求极高
  • 业务上需要连续可读的编号(如订单号、票据号)

数据库中的最佳实践

如果选择 UUID 作为主键,MySQL 中可以将其存储为 BINARY(16) 类型(将 UUID 字符串转为 16 字节二进制),比直接存 VARCHAR(36) 节省约一半空间。PostgreSQL 则提供了原生的 UUID 数据类型,可以直接使用。

对于查询性能敏感的场景,可以考虑使用 UUID v7(时间排序)或雪花算法(Snowflake ID),它们既能满足分布式唯一性,又能保持较好的索引插入顺序。

快速生成 UUID

开发测试或原型验证时,使用我们的 UUID 生成器 可以批量生成 UUID v4(最多 100 个),基于浏览器内置的 crypto.randomUUID() 加密级随机源,一键复制到代码或数据库中。

实战案例:跨库同步中的主键设计

假设一个电商系统早期使用自增 ID,后来为了支持多机房部署,需要把订单数据同步到另一个数据库。此时自增 ID 在两边都从 1 开始,合并时必然冲突。改用 UUID 后,每个节点独立生成主键,无需中央协调,迁移时只要保证字段类型一致即可。类似的场景还包括离线客户端生成草稿 ID、数据仓库从多个业务库汇总数据等。

如果业务量很大,纯随机 UUID 的索引性能可能成为瓶颈。一个折中方案是使用 UUID v7:前 48 位是时间戳,后面是随机部分,主键值随时间增长,数据库 B+ 树插入时更接近顺序追加,减少页分裂。选择前可以先用真实数据量做一次插入性能测试,而不是只看理论结论。

UUID 各版本的更多细节

除了 v1、v4、v7,UUID 还有 v3 和 v5,它们基于命名空间和名称生成,同一个输入永远得到同一个 UUID,适合需要稳定映射的场景。全零 UUID(00000000-0000-0000-0000-000000000000)常被当作"空标识",类似数据库中的 null,实际业务中应避免把它当成正常数据。

v1 包含节点 MAC 地址和时间,理论上可以反推生成时间和设备,存在隐私风险,一般不推荐用于对外暴露的 ID。v4 完全随机,隐私性最好,但排序性能弱。v7 兼顾时间排序与随机性,是 2026 年新建系统的常见选择。

UUID 在 URL 与 API 中的安全价值

使用自增 ID 时,用户可以通过 /order/1001 猜出订单数量,并尝试遍历相邻 ID。UUID 的随机性让枚举成本大幅提高,但要注意:UUID 不是权限控制,不能因为"别人猜不到"就省略鉴权。接口仍必须校验当前用户是否有权访问该资源。

在日志、埋点和外部系统中,UUID 也适合作为事件 ID 或请求追踪 ID。每个请求分配一个 UUID,排障时可以在日志、数据库和前端错误信息中串联完整链路。

存储与迁移实践

MySQL 中把 UUID 字符串直接存为 CHAR(36) 最直观,但会浪费空间,而且按字符串排序和存储的字节序与 UUID 内部排序不一致。更优做法是去掉连字符后转为 BINARY(16),或使用专门的 UUID 函数处理。PostgreSQL 原生支持 UUID 类型,索引和排序都由数据库处理。

迁移时建议先在测试库验证:原有表如果有外键,主键类型变更会连带影响关联表;如果已经用自增 ID 暴露到外部 URL,还要处理旧链接兼容,避免用户收藏和第三方系统失效。

常见问题速查

Q: UUID 一定不会重复吗?

UUID v4 的重复概率极低,理论上不等于绝对不可能。对绝大多数业务而言可以忽略;如果要求绝对唯一,可以加唯一索引并在写入时捕获冲突。

Q: 为什么数据库里 UUID 查询变慢?

通常因为字段存成 VARCHAR 且没有索引,或随机 UUID 导致页分裂。优先使用原生 UUID/BINARY(16),必要时改用 v7 或雪花算法。

Q: 前端可以直接生成 UUID 吗?

可以,现代浏览器提供 crypto.randomUUID(),适合生成客户端 ID。不要使用 Math.random 拼字符串,它的随机性和安全性不足。

Q: UUID 和雪花 ID 怎么选?

UUID 适合跨平台、无状态生成;雪花 ID 需要协调机器 ID 和时间,适合高并发、强顺序要求的内部系统。两者没有绝对优劣。

决策清单

  • 多节点独立生成且需要合并数据时优先 UUID
  • 对外暴露的 ID 不建议使用连续自增
  • 大规模数据优先 v7 或 BINARY(16) 存储
  • UUID 不能替代鉴权,接口仍需权限校验
  • 迁移前验证外键、旧链接和排序行为

小结

自增 ID 和 UUID 各有适用场景,没有绝对的优劣。核心原则是:根据你的架构复杂度、数据规模和业务需求做选择。分布式优先考虑 UUID,简单单体优先考虑自增,折中方案则是 v7 或雪花算法。

参考资料与延伸阅读