SQL主键选择原则_自增与随机主键对比

2次阅读

自增主键是单库场景最优解,因其写入快、索引小、查询稳;uuid等随机主键导致页分裂、io压力大、索引膨胀;仅在全局唯一、语义需求或分库无发号器时才考虑非自增方案。

SQL主键选择原则_自增与随机主键对比

选主键不是挑个字段填上就行,核心是看它怎么影响写入效率、索引结构和系统扩展性。自增主键在单库场景下几乎总是最优解;随机主键(比如 UUID)看似“唯一又安全”,但会实实在在拖慢写入、撑大索引、增加碎片。

为什么自增主键写得快、查得稳

InnoDB 的聚簇索引是 B+ 树,叶子节点存整行数据。自增 ID 递增插入,新记录总追加到当前页末尾:

  • 页面填充率高,很少触发页分裂
  • 避免随机 IO:目标页大概率已在内存中,不用反复从磁盘读取
  • 二级索引体积小——因为索引项里存的是主键值,BIGINT(8 字节)比 UUID(36 字符)省空间、缓存更友好
  • 范围查询(如 WHERE id BETWEEN 1000 AND 2000)天然有序,扫描连续

UUID 这类随机主键的真实代价

UUID 是无序字符串,每次插入都可能落在 B+ 树任意位置:

  • 频繁页分裂:为插入腾位置,要挪动已有数据、拆分页、甚至连锁更新父节点
  • 大量随机读写:目标页常不在 Buffer Pool,需先从磁盘加载,IO 压力陡增
  • 索引膨胀严重:36 字节主键让每个二级索引都多存 36 字节,同样数据量,索引体积可能翻倍
  • 数据物理散乱:相邻逻辑 ID 的行,物理上可能分布在不同数据页,缓存局部性差

什么情况下可以考虑非自增主键

不是不能用,而是得有明确理由,并愿意承担性能折损:

  • 必须全局唯一且不依赖数据库生成:比如多端离线写入、iot 设备直传,雪花算法比 UUID 更优(数字型、时间有序、体积小)
  • 业务要求主键携带语义且不可变:如合规要求用身份证号作主键(但强烈建议用独立 surrogate key,身份证另建唯一索引)
  • 已做分库分表,且无法统一发号器:此时可结合分段自增(如号段模式)或雪花 ID,而非直接上 UUID

一个务实的判断建议

先问自己三个问题:

  • 系统当前是单主写,还是多活/多写?——单主,闭眼选自增
  • 数据量是否接近千万级?QPS 是否常超 500?——没到这规模,自增足够健壮
  • 主键是否要对外暴露(如 URL 中的 /user/123)?——若担心泄露业务量,可在应用层加映射或使用短链,别牺牲底层性能换“隐蔽”
text=ZqhQzanResources