正在加载,请稍候…

UUID vs ULID:你应该使用哪种唯一标识符?

比较 UUID 和 ULID 格式在数据库主键中的应用,了解何时使用每种格式,并即时生成它们。

UUID vs ULID:你应该使用哪种唯一标识符?

什么是唯一标识符?

唯一标识符(UID)是字符串或数字,用于唯一标识数据库、分布式系统或通信协议中的记录。现代软件中最常见的两种格式是 UUID(通用唯一标识符)和 ULID(通用唯一字典序可排序标识符)。

选择错误的格式可能导致数据库性能下降、调试困难或兼容性问题。本指南将解释这两种格式,并帮助您决定使用哪一种。

UUID vs ULID:你应该使用哪种唯一标识符?插图

UUID:通用标准

UUID 在 RFC 4122 中定义,由 128 位组成,显示为 32 个十六进制字符,用连字符分隔:

550e8400-e29b-41d4-a716-446655440000

UUID 版本 4(最常见)对所有字段使用随机位。它大约有 122 位随机性——约 5.3 × 10³⁶ 个可能值。生成 10 亿个 UUID 时发生冲突的概率约为 10²⁰ 分之一。

UUID 版本 来源 用例
v1 MAC 地址 + 时间戳 遗留系统,暴露设备 MAC
v3 命名空间 + 名称的 MD5 哈希 从名称确定性生成
v4 随机 通用 ✅
v5 命名空间 + 名称的 SHA-1 哈希 从名称确定性生成
v7 Unix 时间戳 + 随机 可排序,现代 ✅

ULID:天生可排序

ULID 编码一个 48 位的毫秒时间戳,后跟 80 位随机性,显示为 26 个 Crockford Base32 字符:

01ARZ3NDEKTSV4RRFFQ69G5FAV
│──────────│──────────────│
  10 字符     16 字符
  (时间戳)    (随机)

由于时间戳是前缀,ULID 按字典序按时间顺序排序。在同一毫秒内创建的记录共享时间戳前缀,但随机后缀不同,从而保持唯一性。

UUID vs ULID:你应该使用哪种唯一标识符?插图

直接对比

特性 UUID v4 UUID v7 ULID
字符串长度 36 字符 36 字符 26 字符
可排序 ❌ ✅ ✅
URL 安全 需要编码 需要编码 ✅
包含时间戳 ❌ ✅ ✅
标准化 RFC 4122 RFC 9562 (2024) 社区规范
数据库索引性能 碎片化 良好 良好
可读性 低 低 中等

数据库性能:为什么可排序性很重要

在 B 树索引(PostgreSQL、MySQL)中,顺序插入比随机插入高效得多。UUID v4 的随机性导致索引碎片化:每个新行插入到索引树中的随机位置,导致频繁的页分裂和缓存未命中。

ULID 和 UUID v7 通过使用单调递增的值(大多数情况下)解决了这个问题,允许新记录追加到索引末尾附近,从而在高吞吐量系统中显著减少写入开销。

来自各种 PostgreSQL 实验的基准数据显示,在大型表(1 亿行以上)上,使用可排序 ID 的插入性能提高了 3–5 倍。

UUID vs ULID:你应该使用哪种唯一标识符?插图

何时使用 UUID v4

  • 最大兼容性——每个数据库、语言和框架都理解 UUID。
  • 无时间戳泄露——如果您不希望 ID 中嵌入创建时间。
  • 简单集成——在 SQL(PostgreSQL 13+ 中的 gen_random_uuid())、Node.js(crypto.randomUUID())、Python(uuid.uuid4())中可用。
  • 低到中等吞吐量——对于大多数每天记录量低于数百万的应用程序来说足够。

何时使用 ULID

  • 高写入数据库——事件溯源、日志、审计跟踪。
  • URL 安全 ID——没有连字符或特殊字符。
  • 调试——您可以从 ULID 本身提取创建时间。
  • 排序列表——用作分页游标,无需单独存储 created_at。

何时使用 UUID v7

UUID v7(在 RFC 9562 中正式化,2024 年 4 月)提供了两全其美的方案:标准 UUID 格式,嵌入 Unix 时间戳以实现可排序性。它在数据库(PostgreSQL 17+)和库中得到越来越多的支持。对于新项目,UUID v7 通常是最佳选择。

实用代码示例

// UUID v4 — Node.js 内置
const { randomUUID } = require('crypto');
const id = randomUUID(); // "550e8400-e29b-41d4-a716-446655440000"

// ULID — npm 包
import { ulid } from 'ulid';
const id = ulid(); // "01ARZ3NDEKTSV4RRFFQ69G5FAV"
-- PostgreSQL UUID v4
SELECT gen_random_uuid();

-- PostgreSQL UUID v7 (pg 17+ 或 pgcrypto 扩展)
SELECT uuid_generate_v7();

→ 尝试 UUID 生成器 或 ULID 生成器