MySQL 自增主键在写入性能上通常优于 UUID,因为自增 ID 顺序插入减少页分裂并提升缓存命中率,而 UUID 随机插入会导致频繁页分裂和随机 I/O。除非业务强依赖分布式唯一性且已接受性能折损,否则默认推荐自增主键。
先说结论:自增主键索引性能通常优于 UUID,因其顺序插入减少页分裂、提升缓存局部性、降低 I/O 开销;UUID 仅在分库分表或数据合并等强分布式场景下才应选用。
- 适合:高并发写入、范围查询频繁、存储空间敏感的单实例或主从架构。
- 重点看:B+ 树索引的页分裂情况和缓冲池命中率,UUID 随机性会直接破坏局部性。
- 别忽略:UUID 作为聚簇索引会导致所有二级索引体积膨胀,每条记录多占 16 字节以上。
命令速用版
若需快速建表对比,可参考以下结构定义,注意 UUID 建议转为 BINARY 存储以减少空间占用。
CREATE TABLE users_autoinc ( id BIGINT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) );
CREATE TABLE users_uuid ( id BINARY(16) PRIMARY KEY, name VARCHAR(100) );
为什么会这样
自增 ID 在 B+ 树索引中更快,因为 InnoDB 聚簇索引按主键顺序存储数据行,自增 ID 每次插入都追加到末尾,页分裂极少。UUID 是随机字符串,插入位置不可预测,导致频繁页分裂、大量随机 I/O 和索引碎片,INSERT 延迟可能从 0.2–0.5ms 升至 1.5–4ms。
分步处理
根据业务场景选择主键类型,若必须用 UUID 需进行优化处理。
- 评估分布式需求:若无需跨实例全局唯一,优先选自增 BIGINT。
- 优化 UUID 存储:若必须用 UUID,不要用 CHAR(36),改用 BINARY(16) 配合 UUID_TO_BIN() 函数。
- 调整锁模式:MySQL 8.0+ 可开启 innodb_autoinc_lock_mode = 2 减少自增锁争用,但要求 binlog_format = ROW。
怎么验证是否生效
通过慢查询日志和状态变量监控写入延迟与 IO 情况。
- 检查慢日志:观察 INSERT 语句的 Query_time,UUID 表在高写入下延迟明显更高。
- 监控缓冲池:观察 Innodb_buffer_pool_reads,若持续上升说明磁盘 IO 被迫介入。
- 查看索引基数:执行 SHOW INDEX FROM table_name,若 Cardinality 严重偏低可能是索引碎片导致。
常见坑
- 自增主键高并发易锁表:秒杀场景下 AUTO_INCREMENT 锁争用可能导致串行化写入。
- UUID 直接存字符串:CHAR(36) 比 BIGINT 多占 4.5 倍空间,且无法走索引优化。
- 误用 UUID 做业务序号:自增 ID 回滚或批量失败会跳变,不适合暴露给前端作为订单号。
常见问题
UUID 做主键真就完全不行吗?
不是完全不行,但代价大。如果业务强依赖分布式生成 ID,至少别用原生 UUID() 函数,改用 BINARY(16) 存储能挽回一部分性能损失,但无法根治随机性问题。
自增 ID 在分库分表下怎么解决冲突?
分库分表且无全局序列服务时,各实例独立生成 UUID 可保唯一,或者使用 Snowflake 算法生成全局唯一自增 ID 替代原生 AUTO_INCREMENT。
参考来源
- mysql 数据库主键类型对性能的影响_使用自增整数优于 UUID
- mysql 如何选择主键 ID 方案_对比自增 ID 与 UUID 的索引性能
- MySQL/PostgreSQL 数据库主键用 UUID 还是自增 ID? 一次性能压测与存储空间的完整对比
- SQL 主键自增序列 vs UUID 主键的插入性能与索引碎片对比
- 深度实测:Mysql UUID 主键性能全解析与优化指南