<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>uuid on </title>
    <link>/tags/uuid/</link>
    <description>Recent content in uuid on </description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Tue, 08 Sep 2026 13:37:38 +0800</lastBuildDate><atom:link href="/tags/uuid/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>UUIDv4 / UUIDv7 / ULID 当主键的取舍：键宽和递增性在四种部署形态下的收益和代价</title>
      <link>/posts/distributed-id-uuidv4-uuidv7-ulid/</link>
      <pubDate>Tue, 08 Sep 2026 13:37:38 +0800</pubDate>
      
      <guid>/posts/distributed-id-uuidv4-uuidv7-ulid/</guid>
      <description>分布式系统里的 ID 要在互不协调的多个节点上各自生成，所以候选基本都是 128 位：UUIDv4 全是随机数，UUIDv7 和 ULID 前面放毫秒时间戳、后面放随机数。
三个里选哪个，绕不开一句常见的建议：主键最好递增。选型真正在选的只有两件事：键占几个字节，同一毫秒内有没有顺序。这两件事各换来什么、要付什么，取决于几个进程在写、数据靠什么分布。
一个写入者的 InnoDB 表上递增的收益最大：同一张 30 万行的表，主键从纯随机换成同一毫秒内严格递增，聚簇索引少近四成的页。四个实例各带计数器时只剩两成，键存成 CHAR(36) 时反而比纯随机多两成页；按主键范围分片的库上递增变成写热点；按 hash 分布的库不看这一项。
只有前两种形态是我自己量的：单节点 MySQL 能在一台笔记本上反复跑，而且它的 fill factor 规则手册里写着，可以拿实测去对。分片那两种按各家文档说，不报没测过的数。
环境是 MySQL 8.0.46（mysql:8.0 容器，innodb_buffer_pool_size=128M，binlog 开着）。建表脚本、灌数脚本和原始输出在 distributed-id-demo：八张表的页数在 results/2026-09-08-innodb.txt，OPTIMIZE TABLE 前后的对照在 results/2026-09-08-innodb-reclaim.txt。
一处口径先交代清楚：灌数用的键是脚本预先生成的，键里的毫秒时间戳每 500 行进一格，模拟每毫秒写 500 条，不是灌数时的真实速率。
三种 ID 的位段：时间戳在前，随机位在后 三种 ID 都是 128 位，差别在这 128 位怎么切。随机位的宽度取自规范本身，不是谁的实测。
时间戳 随机位 文本形态 出处 UUIDv4 无 122 36 字符十六进制，带连字符 RFC 9562 §5.4 UUIDv7 48 位，Unix 毫秒 74（rand_a 12 + rand_b 62） 36 字符十六进制 RFC 9562 §5.</description>
    </item>
    
  </channel>
</rss>
