DevToolBox免费
博客

UUID v4 vs UUID v7 vs ULID vs NanoID:你应该用哪种 ID?

10 分钟阅读作者 DevToolBox
Ad Space

为应用程序选择正确的唯一标识符格式是一个影响数据库性能、可扩展性和开发者体验的决策。随着 UUID v7 成为正式标准(RFC 9562,2024 年发布),ID 生成的格局已经发生了重大变化。本指南比较了四种最流行的选项。

快速对比表

特性UUID v4UUID v7ULIDNanoID
大小(字节)161616Configurable (default 21 chars)
字符串长度36 chars36 chars26 chars21 chars (default)
时间有序NoYes (ms precision)Yes (ms precision)No
标准RFC 9562RFC 9562Community specCommunity spec
数据库索引友好PoorExcellentExcellentPoor
抗碰撞性122 random bits74 random bits + timestamp80 random bits + timestampConfigurable
URL 安全Yes (with encoding)Yes (with encoding)Yes (native)Yes (native)
语言支持UniversalGrowing rapidlyGoodExcellent (JS/TS)

UUID v4:成熟的标准

UUID v4 十多年来一直是默认选择。它使用 122 位随机数生成 128 位标识符,产生熟悉的 xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx 格式。

优势:

  • 在所有编程语言中都有通用的库支持
  • 无需协调——随时随地生成
  • 简单且易于理解

劣势:

  • 随机分布导致数据库中的 B-tree 索引碎片化
  • 没有时间信息——无法按创建顺序排序
  • 在大规模(数百万行)情况下,插入性能显著下降
// JavaScript
crypto.randomUUID();
// → "f47ac10b-58cc-4372-a567-0e02b2c3d479"

试用我们的 UUID 生成器工具 →

UUID v7:新标准(RFC 9562)

UUID v7 在 RFC 9562(2024)中最终确定,专门设计用作数据库键。它将 48 位 Unix 时间戳(毫秒精度)与 74 位随机数结合,生成与现有 UUID 基础设施完全兼容的时间有序 UUID。

优势:

  • 时间有序——自然按创建时间排序
  • 优秀的数据库插入性能(无索引碎片化)
  • 与所有现有的 UUID 列和工具兼容
  • PostgreSQL 17+ 原生支持

劣势:

  • 随机位更少(74 vs 122)——但仍具有极高的抗碰撞性
  • 时间戳被嵌入——会暴露大致的创建时间
  • 库支持仍在增长中(但增速很快)
// Node.js (uuid library v9+)
import { v7 as uuidv7 } from 'uuid';
uuidv7();
// → "018e4f5c-6a7b-7000-8000-1234abcd5678"
//    ^^^^^^^^^^^^^^^^ timestamp portion

ULID:可字典序排序

ULID(Universally Unique Lexicographically Sortable Identifier)早于 UUID v7,并共享类似的设计:48 位时间戳 + 80 位随机数。关键区别在于其编码方式:Crockford Base32,生成紧凑的 26 字符字符串,如 01ARZ3NDEKTSV4RRFFQ69G5FAV

优势:

  • 紧凑的字符串表示(26 个字符 vs UUID 的 36 个)
  • 内置单调性——在同一毫秒内生成的 ID 仍然有序
  • 作为字符串可字典序排序(无需特殊比较)
  • 大小写不敏感且 URL 安全

劣势:

  • 不是 RFC 标准——仅为社区规范
  • 不经过转换则与 UUID 列不兼容
  • 比 UUID 的库支持更少
// JavaScript
import { ulid } from 'ulid';
ulid();
// → "01ARZ3NDEKTSV4RRFFQ69G5FAV"

NanoID:紧凑且可定制

NanoID 采用了不同的方法:它不使用固定格式,而是生成紧凑的、URL 安全的随机字符串,具有可配置的字母表和长度。默认值为 21 个字符,使用 A-Za-z0-9_-

优势:

  • 非常紧凑(默认 21 个字符,可定制)
  • 默认 URL 安全
  • 可定制的字母表和长度
  • 极小的库(gzip 后约 130 字节)——非常适合前端
  • 加密强度高(使用 crypto.getRandomValues)

劣势:

  • 无时间排序——与 UUID v4 存在相同的 B-tree 碎片化问题
  • 没有标准规范
  • 与 UUID 基础设施不兼容
// JavaScript
import { nanoid } from 'nanoid';
nanoid();
// → "V1StGXR8_Z5jdHi6B-myT"

决策指南:你应该选择哪个?

在以下情况使用 UUID v7:

  • 使用关系型数据库构建新应用
  • 需要时间有序的 ID 以实现高效索引
  • 系统期望标准 UUID 格式(PostgreSQL、MySQL 等)
  • 希望获得兼容性和性能的最佳平衡

在以下情况使用 UUID v4:

  • 使用仅支持 UUID v4 的系统
  • 需要最大随机性且不泄露时间戳
  • 数据库规模为中小型(< 100 万行)

在以下情况使用 ULID:

  • 需要更短的字符串表示
  • 使用按字典序排序字符串的系统
  • 同一毫秒内的单调性很重要
  • 不需要 UUID 列兼容性

在以下情况使用 NanoID:

  • 在浏览器或前端生成 ID
  • 包大小很重要(NanoID 仅 130 字节)
  • 需要短小的、URL 友好的标识符
  • 构建 URL 缩短器、邀请码或会话令牌

性能基准测试:数据库插入

这些格式之间最具影响力的区别是数据库插入性能。时间有序的 ID(UUID v7、ULID)保持顺序 B-tree 插入,而随机 ID(UUID v4、NanoID)导致随机页面分裂:

ID 格式100 万次插入(PostgreSQL)索引大小插入模式
自增~12s (baseline)21 MBSequential
UUID v7~15s (+25%)56 MBNearly sequential
ULID~15s (+25%)56 MBNearly sequential
UUID v4~28s (+133%)56 MBRandom
NanoID (21 chars)~30s (+150%)62 MBRandom

基准测试数据为近似值,会因硬件、数据库版本和表结构而异。相对差异在所有环境中保持一致。

迁移路径:UUID v4 到 UUID v7

如果你正在考虑从 UUID v4 迁移到 UUID v7,好消息是它们共享相同的 128 位格式和字符串表示。在大多数数据库中,你可以开始为新行生成 UUID v7 值,同时现有的 UUID v4 值保持有效:

-- PostgreSQL 17+
CREATE TABLE users (
  id UUID DEFAULT gen_random_uuid_v7() PRIMARY KEY,
  name TEXT NOT NULL
);

-- Older PostgreSQL with uuid-ossp or pgcrypto
-- Use application-level UUID v7 generation

常见问题

我应该从 UUID v4 迁移到 UUID v7 吗?

如果你的应用使用 UUID 作为数据库主键,并且在大规模情况下遇到索引碎片化或插入缓慢的问题,那么迁移到 UUID v7 值得考虑。对于中小型应用,UUID v4 工作正常。

NanoID 适合用作数据库主键吗?

NanoID 具有加密安全性和可配置长度,但缺少时间排序。对于插入性能很重要的数据库主键,UUID v7 或 ULID 是更好的选择。NanoID 在前端应用和 URL 缩短器中表现出色。

UUID v7 和 ULID 之间有什么区别?

两者都是时间有序的唯一标识符。UUID v7 遵循 RFC 9562,与现有 UUID 基础设施兼容(128 位,标准格式)。ULID 使用 Crockford Base32 编码(26 个字符),并在同一毫秒内具有内置单调性。UUID v7 更适合期望 UUID 格式的系统;ULID 作为字符串更紧凑。

试试这些相关工具

IDUUID Generator
Ad Space

相关文章

Base64 编码实战:每个开发者都应该知道的 7 个真实用途

发现 Base64 编码的 7 个实际应用:HTML 嵌入图片、Kubernetes Secrets、JWT Token、Data URI 等。