UUID v7 实战:可按时间排序的主键,以及它和 v4 的真正区别
UUID v7 把毫秒时间戳放进开头,因此当字符串排序就是按时间排。本文讲清它的 48 位时间戳结构、和全随机 v4 的差别,以及为什么它更适合做数据库主键。
UUID v7 实战:可按时间排序的主键,以及它和 v4 的真正区别
我第一次给一张高写入表换主键,是因为线上插入越来越慢。表用的是随机 UUID v4,几百万行之后,索引碎片化把每次 insert 都拖成一次磁盘随机写。换成 UUID v7 之后,同样的写入压力,插入延迟肉眼可见地降了下来。这篇就把我当时弄明白的几件事讲清楚:v7 的结构、它和 v4 差在哪,以及为什么它做主键更省心。
你可以边读边用 UUID v7 生成器 生成几个看实际格式,也能把任意一个 v7 粘进它的解码器,把内嵌的时间戳直接读出来。
v7 到底长什么样
UUID v7 由 RFC 9562 规定,这份标准 2024 年 5 月发布,取代了沿用十多年的 RFC 4122,正式把"时间有序"的 v7 布局写进规范。它依然是 128 位,依然是熟悉的 8-4-4-4-12 十六进制外形,区别全在内部的位分配。
从高位往低位看,一个 v7 是这样切分的:
- 最高 48 位:Unix 毫秒时间戳,大端存放。
- 接着 4 位:版本号,固定为 0111,也就是十六进制的 7。
- 再 12 位:随机。
- 然后 2 位:变体标记,固定为 10。
- 剩下 62 位:随机。
也就是说,前 12 个十六进制字符就是创建时刻的毫秒数,后面才是保证唯一性的随机尾巴。这个布局是它一切好处的来源。
和 v4 的真正区别:排序
v4 是全随机的 122 位有效位,除了版本和变体那几位,其余全靠随机数发生器。它的优点是不透明,看一眼猜不出任何信息;缺点是两个相隔片刻生成的 v4 之间,完全没有先后关系。
v7 不一样。因为开头就是时间戳,先生成的 ID 在数值上一定小于后生成的。把它们当成普通字符串去排,排出来的顺序就是创建顺序。举个真实的例子,把这个 v7 粘进解码器:
0190b3b0-6400-7000-8000-000000000000
它的前 12 位 0190b3b0-6400 解出来是 1721001600000 毫秒,也就是 2024-07-15 00:00:00 UTC。任何一个 2024-07-15 之后生成的 v7,字符串比较都会排在它后面。这就是 v7 能"按时间排序"的全部魔法,不需要额外的列,信息就写在 ID 自己身上。
为什么它更适合做主键
关键词是索引局部性。数据库主键通常落在 B-tree 上,而 B-tree 最怕的就是随机写入。
随机的 v4 会把新行撒满整棵树,每次插入命中的页都不一样,缓存里刚热起来的页转头又被换出去,索引也随着不断分裂、碎片化。在写入密集的表上,这种代价非常实在。
v7 因为以时间戳开头,新生成的 ID 在数值上彼此相近,插入几乎都集中在索引的右端。页面保持热,页分裂变少,工作集更紧凑。顺带还有一个好处:ORDER BY id 直接就是按创建时间排,取最新 50 行写成 ORDER BY id DESC LIMIT 50 就够了,不用再单独维护一个 created_at 列再给它建索引。Postgres 18 和 SQL Server 现在都内置了 v7 风格的生成器,正是冲着这个场景去的。
一个该记住的坑
v7 好用,但别把它当密钥。随机位让碰撞几乎不可能,可开头那 48 位是完全可读的时间戳。换句话说,任何拿到这个 ID 的人都能解出它大致的创建时间,相邻的单调 ID 甚至会暴露你创建记录的速度。
所以 v7 是标识符,不是令牌。别拿它做会话密钥、密码重置码,或任何必须整体不可猜的东西。如果创建时间本身是敏感信息,就把 v7 留在内部,对外再给一个不透明的别名。校验的时候也要留神:别用放行任意 8-4-4-4-12 的通用正则,那会把 v4 甚至全零的 NIL UUID 也当合法,正确做法是检查第 13 个字符是不是 7、变体位是不是 10。
怎么挑生成方式
如果你需要的是标准、能直接塞进数据库 UUID 列、被各种库和框架接受的有序 ID,那 v7 是最稳的选择。它和 ULID 思路相同,都是时间戳加随机,但 v7 是 RFC 认可的标准 UUID,不用做编码转换。
要快速验证格式、批量生成、或者反查某个 ID 的创建时间,直接用 UUID v7 生成器 就行,它支持一次生成 1 到 100 个、单调递增模式,以及把时间戳读回来的解码器,全程在浏览器本地完成。如果你的场景其实只要一个不透明的随机标识,不在意排序,那经典的 UUID 生成器 反而更合适,没必要为了排序而泄露时间。
选对了主键类型,后面省下的运维心力,比你想象的多。
Made by Toolora · Updated 2026-06-13