DevToolbox
All articles

UUID生成器使用指南:原理、版本区别与最佳实践

· 7 min read

UUID(Universally Unique Identifier,通用唯一识别码)是现代软件开发中最常用的标识符方案之一。无论是数据库主键、分布式事务追踪、还是文件命名,UUID 都能保证在不依赖中央协调机构的前提下,生成全局唯一的标识符。本文将深入讲解 UUID 的格式、各版本的区别,以及在实际项目中的最佳实践。

UUID 是什么

UUID 是一个 128 位(16 字节)的数字,通常以 32 个十六进制字符加上 4 个连字符的形式表示,格式为 8-4-4-4-12

550e8400-e29b-41d4-a716-446655440000

上面这个例子总共包含 32 个十六进制字符,对应 128 位。其中第三组的第一个字符表示 UUID 的版本号,第四组的第一个字符表示变体(variant),用来区分不同的 UUID 规范。

UUID 的理论碰撞概率极低。以 v4(随机版本)为例,要使碰撞概率达到 50%,需要生成约 2.71 × 10¹⁸ 个 UUID。在绝大多数应用场景下,UUID 可以视为绝对唯一。

UUID 各版本的区别

UUID 规范目前定义了多个版本,不同版本的生成方式和适用场景各有不同。以下是最常见的几个版本:

v1:基于时间和 MAC 地址

UUID v1 使用当前时间戳(精确到 100 纳秒)和网卡 MAC 地址来生成。这种方式保证了时间上的有序性,但也带来了隐私问题——MAC 地址会被嵌入 UUID 中,可以追溯到具体的机器。此外,在同一台机器上高频生成时需要引入随机偏移来避免碰撞。

  • 优点:时间有序,便于数据库索引
  • 缺点:泄露 MAC 地址,隐私风险较高

v4:纯随机

UUID v4 完全基于随机数生成,除了版本和变体位以外,其余 122 位都是随机的。这是目前使用最广泛的版本,简单、安全、不依赖任何机器信息。绝大多数编程语言和框架的默认 UUID 生成方法都产生 v4 UUID。

  • 优点:完全随机,无信息泄露
  • 缺点:无序,作为数据库主键时会引发索引碎片化

v7:时间有序的随机 UUID(推荐用于数据库)

UUID v7 是 2022 年新草案中引入的版本,将毫秒级 Unix 时间戳编码到 UUID 的高位部分,低位仍为随机数。这使得 v7 UUID 既具备 v4 的随机性,又具备 v1 的时间有序性,同时不泄露任何机器信息。

  • 优点:时间有序、随机性好、适合数据库主键
  • 缺点:部分旧版语言库尚未原生支持,需要第三方库

UUID 与 GUID 的关系

很多开发者在 Windows 开发或使用 .NET、COM 技术栈时会接触到 GUID(Globally Unique Identifier)这一术语。实际上,GUID 和 UUID 是同一标准——GUID 是微软对 UUID 规范的称呼,两者完全兼容,格式也完全相同。

唯一的细微差别在于:微软的某些工具在展示 GUID 时会加上花括号,例如 {550e8400-e29b-41d4-a716-446655440000},而标准 UUID 格式不带花括号。在代码中处理时,通常只需去掉花括号即可互通使用。

在代码中生成 UUID

以下是主流语言和数据库中生成 UUID 的标准方法:

JavaScript / TypeScript

现代浏览器和 Node.js 18+ 均内置了 crypto.randomUUID(),生成的是 v4 UUID,无需安装任何依赖:

// 浏览器或 Node.js 18+
const id = crypto.randomUUID();
console.log(id); // 例如:'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'

如果需要在旧版 Node.js 中使用,可以用 uuid 包:

// npm install uuid
import { v4 as uuidv4, v7 as uuidv7 } from 'uuid';

const idV4 = uuidv4(); // v4 随机 UUID
const idV7 = uuidv7(); // v7 时间有序 UUID(需要 uuid@9+)

Python

Python 标准库内置了 uuid 模块,无需安装第三方包:

import uuid

# 生成 v4 UUID(最常用)
id_v4 = uuid.uuid4()
print(str(id_v4))  # 例如:'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'

# 生成 v1 UUID
id_v1 = uuid.uuid1()
print(str(id_v1))

MySQL

-- 生成 v1 UUID(MySQL 内置)
SELECT UUID();
-- 结果:'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'

-- 去掉连字符,存为 CHAR(32)
SELECT REPLACE(UUID(), '-', '');

PostgreSQL

-- PostgreSQL 13+ 内置 gen_random_uuid(),生成 v4
SELECT gen_random_uuid();
-- 结果:'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'

-- 也可以启用 pgcrypto 扩展
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
SELECT gen_random_uuid();

UUID 作为数据库主键的优缺点

将 UUID 用作数据库主键是一个常见但有争议的设计决策。了解其优缺点有助于在具体场景中做出正确选择。

优点

  • 分布式友好:无需数据库自增序列,多个服务、多个数据库节点可以独立生成不冲突的主键,非常适合微服务和分布式系统。
  • 安全性更好:相比自增整数 ID(如 123),UUID 不会暴露数据库中的记录数量,也难以被遍历枚举。
  • 数据迁移方便:合并来自不同数据库的数据时,UUID 不会产生主键冲突。

缺点

  • 索引碎片化:v4 UUID 完全随机,每次插入新记录时,B-tree 索引都需要在随机位置插入,导致页分裂频繁,索引碎片化严重,写入性能随数据量增长而明显下降。
  • 存储空间较大:UUID 占 16 字节,而 BIGINT 只占 8 字节。如果主键上有大量二级索引,存储开销会显著增加。
  • 可读性差:调试时查看日志,UUID 不如自增整数直观。

为什么推荐 UUID v7 用于数据库

UUID v7 解决了 v4 最大的痛点——索引碎片化。由于 v7 的高位包含毫秒级时间戳,新生成的 UUID 总是大于旧的 UUID,插入操作总是追加到 B-tree 索引的末尾,与自增整数的行为一致,避免了页分裂。

同时,v7 的低位仍然包含足够的随机性(约 74 位),在同一毫秒内批量生成时也不会产生碰撞。可以说,UUID v7 是目前综合性能最好的 UUID 版本,新项目应优先考虑使用。

如果所用语言或框架暂不支持 v7,也可以考虑使用 ULID(Universally Unique Lexicographically Sortable Identifier)作为替代方案,它同样具备时间有序性,且格式更紧凑。

总结

UUID 是现代开发中不可缺少的工具。日常业务中生成随机 ID 用 v4(或直接用 crypto.randomUUID())足够了;如果 UUID 要作为数据库主键且对写入性能有要求,应优先选择 v7。理解 UUID 的原理和各版本特性,能帮助你在架构设计时做出更合理的决策。

Try it free
UUID 生成器
100% client-side · no signup · no upload
Open tool →