大数据库场景下应选UUID做主键还是增设INT主键将UUID设为唯一键
InnoDB场景下UUID主键方案选择建议
核心前提:InnoDB聚簇索引的存储特性
InnoDB的表数据是直接和主键绑定的聚簇索引结构,所有数据行按照主键的排序规则物理存储在B+树的叶子节点上,写入时如果新的主键值不是递增的,就需要在现有B+树的随机位置插入数据,当对应数据页满了之后就会触发页分裂操作。
两种方案的优劣对比
方案1:直接使用随机UUID作为主键
- 劣势非常明显:随机UUID的无序性会导致频繁的页分裂,数据页的存储利用率通常只有50%左右,同等数据量下存储开销比顺序主键高接近一倍,单表数据量超过百万级之后,写入IOps开销会陡增,插入延迟波动非常大
- 额外劣势:如果后续新增二级索引,二级索引的叶子节点需要存储主键值,16字节的UUID比8字节的BIGINT占用空间大一倍,会进一步放大存储和查询IO开销
方案2:自增BIGINT主键 + BINARY(16) UUID唯一键
- 优势1:自增主键是完全顺序写入,不会触发不必要的页分裂,数据页利用率可以达到90%以上,存储成本更低,大数据量下写入性能比随机UUID主键高2~5倍,延迟非常稳定
- 优势2:UUID作为二级唯一索引维护,虽然插入时多了一次二级索引的写入开销,但这个开销远低于聚簇索引频繁页分裂带来的额外开销,长期大数据量场景下整体性能表现好得多
- 优势3:对外暴露的检索入口仍然是UUID,完全不影响原有业务的安全设计和接口逻辑,内部存储逻辑和外部业务完全解耦
特殊场景例外
如果你可以将随机UUID替换为有序UUID(比如使用MySQL 8.0内置的UUID_TO_BIN(UUID(), 1)函数生成带时间前缀的有序UUID,或者业务侧生成带时间序的UUIDv1、UUIDv7),那么完全可以直接将有序UUID设为主键:有序UUID的写入是近乎顺序的,不会出现大量页分裂问题,同时还省了维护自增主键的逻辑,兼顾性能和业务需求。
最终建议
如果你当前使用的是普通随机UUID,优先选择自增BIGINT主键 + UUID唯一键的方案,更适合潜在的大数据量场景;如果可以切换为有序UUID,直接用有序UUID作为主键也是合理选择。
内容的提问来源于stack exchange,提问作者Jamie Poole
相关产品推荐
相关产品推荐

