自增主键索引性能通常优于uuid,因其顺序插入减少页分裂、提升缓存局部性、降低i/o开销;uuid因随机性导致频繁页分裂、索引膨胀及查询劣化,仅在分库分表或数据合并等强分布式场景下才应选用。

MySQL 用自增 AUTO_INCREMENT 做主键,索引性能几乎总是优于 UUID;除非你明确需要分布式唯一性且已接受性能折损,否则别默认选 UUID。
自增ID为什么在B+树索引里更快
InnoDB 的聚簇索引把数据行和主键绑在一起存,而 B+ 树要求叶子节点按主键顺序链接。自增 id 每次插入都追加到末尾,页分裂极少,缓存局部性好——相邻 ID 的数据大概率在同一个数据页或相邻页里。
- INSERT 新记录基本不触发页分裂,
INSERT延迟稳定在 0.2–0.5ms -
ORDER BY id是天然有序扫描,走索引即可,不用全表扫 - 单个数据页能塞下更多行(因为主键只占 4 或 8 字节),1000 万行表可省约 160MB 索引空间
- 高并发插入时,虽然有
AUTO_INCREMENT锁争用风险,但远不如 UUID 随机写带来的 I/O 压力严重
UUID做主键的索引代价到底在哪
UUID 是随机字符串(如 '550e8400-e29b-41d4-a716-446655440000'),插入位置完全不可预测,直接破坏 B+ 树的局部性。
- 每插一条都可能引发页分裂:已有页填满后要拆成两页,再重排指针,I/O 成倍增加
- 缓存命中率暴跌:刚读过的页,下次很可能完全无关,
SELECT更多依赖磁盘随机读 - 索引体积膨胀:CHAR(36) 实际存 36 字节,比
BIGINT多占 4.5 倍空间;二级索引也跟着变胖 -
WHERE id BETWEEN ? AND ?退化为全索引扫描,因值无序,无法利用 B+ 树范围跳转
如果非要用UUID,至少别用CHAR(36)
用 CHAR(36) 是最差选择;改用 BINARY(16) + UUID_TO_BIN() 能挽回一部分性能损失,但无法根治随机性问题。
- 建表时用
id BINARY(16) PRIMARY KEY DEFAULT (UUID_TO_BIN(UUID())) - 插入时必须用
UUID_TO_BIN()转换,不能直接插字符串,否则索引失效 - 查询时也要用
BIN_TO_UUID()转回可读格式,业务层需适配 - 即便如此,插入耗时仍比自增 ID 高 2–3 倍,页分裂频率只降不除
什么时候该放弃自增ID
不是“性能够用就换”,而是“业务约束逼你换”。典型场景只有两个:
- 分库分表且无全局序列服务(如 Snowflake)时,各实例独立生成 UUID 可保唯一
- 需频繁合并多个数据库的数据(比如迁移、归档),UUID 天然避碰,不用人工重映射主键
其他所谓“安全”“防爬”“分布式友好”,都可以通过加一层映射表或前端脱敏解决,没必要拿索引性能换。











