连载中 2/16

UUID:最顺手的瑞士军刀,最差的订单主键

2026-06-06 · 5538 阅读 · 0 评论 · 0 赞

事故后的第一反应

退款事故复盘会上,同事小刘第一个举手:换 UUID 啊!本地生成、不用协调、概率上全球不重复,一行代码的事。老王先点头——这确实是分布式 ID 的第一候选——然后打开订单表的空间监控:如果真换了,订单主键索引要涨三倍多。UUID 是好东西,但好东西也要看放哪。这篇把它的功与过拆清楚。

先认清这把刀

UUID 是 128 位的标识符,标准写法 36 个字符,按 8-4-4-4-12 分段:550e8400-e29b-41d4-a716-446655440000。它是个家族,不是一种东西:

版本怎么生成特点
v1时间戳加 MAC 地址有序但泄露机器 MAC,时序字段在高位尾部
v3 / v5命名空间加名字做哈希同名同号,可用于幂等去重
v4纯随机 122 位最常用,完全无序
v7毫秒时间戳打头加随机尾部趋势有序,2024 年进 RFC 9562 的新宠

Java 里 UUID.randomUUID() 用的就是 v4。它的核心优势一句话:发号不依赖任何人——没有 DB、没有 Redis、没有协调服务,本机生成,吞吐只受 CPU 限制。122 位随机空间,一纳秒生成一个也要上百亿年才有可观碰撞概率,唯一性靠概率而非协调,这是它和后面所有方案的本质区别。

当 InnoDB 主键的三重暴击

优势讲完,泼三盆冷水。第一盆:无序写,页分裂狂魔。InnoDB 是聚簇索引,数据按主键物理有序存放。自增 ID 永远往最后一页追加;v4 UUID 随机落点,新行可能插到任何一页——页满了就分裂、挪数据、维护父节点,写放大直接拉满。写入吞吐掉一个量级不是夸张,是 MySQL 系列里页分裂机制(第 2 篇)的必然结果。

第二盆:太肥,索引全面膨胀。bigint 主键 8 字节,UUID 存成 char(36) 是 36 字节起步。更要命的是 InnoDB 的二级索引叶子节点都存着一份主键值——订单表十几个二级索引,每个都要跟着胖。老王算过账:一亿行的订单表,主键从 bigint 换成 UUID,光索引空间多出几个 GB,缓冲池里能缓存的页少了,命中率跟着掉。索引是一寸金一寸土的地方。

第三盆:语义为零。随机串没有时间信息、没法排序、没法范围查询,按时间拉订单还得回表查别的列。运营说「把昨晚八点后的订单拉出来」,自增 ID 和雪花 ID 都能走主键范围,UUID 只能全表筛。

v7 与 ULID:改良,但没根治

社区早就看穿了无序的痛点,给出两条改良路线:UUID v7 把毫秒时间戳放在最高位,整体趋势有序,插入落点集中在 B+ 树右侧,页分裂大幅缓解;ULID 同思路,128 位里时间戳占 48 位,剩下的随机,还做了大小写友好的 Crockford 编码。两者都值得收录进工具箱。

但注意改良的边界:时间戳前缀牺牲了一点随机性(同一毫秒内的序靠随机尾部维持),并且长度问题纹丝没动——128 位还是 128 位,索引还是那么肥。所以 v7 适合替代 v4 的场合,不适合替代 bigint 主键的场合。

场景判断:什么时候用,什么时候别用

场景用不用理由
链路追踪 traceId用全链路透传,不落库索引,无序无所谓
幂等键、去重键用v3/v5 同名同号的特性正好
离线数据同步冲突避免用两端各自生成不打架
订单表主键别用无序写页分裂加索引膨胀
需要按时间范围检索的表别用 v4语义为零,范围查询全靠回表

小结

UUID 一句话:解决唯一性的成本最低,但把成本转嫁给了索引和写入。它是最顺手的瑞士军刀——traceId、幂等键、离线同步样样精通;当订单主键却是三重暴击。数据库主键需要的是趋势递增,这就引出下一步:继续让数据库发号,但换一种聪明的方式——号段模式。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#分布式ID#UUID#ULID#主键#页分裂

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9873 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9294 阅读 · 21 评论 · 287 赞