1. 为什么MySQL不推荐用字符串做主键?
前几天帮同事排查一个性能问题,发现他们用UUID做主键的表查询速度比用自增ID的慢了近10倍。这让我想起一个老生常谈的话题:在MySQL中到底该不该用UUID这类字符串作为主键?今天就从存储结构、索引机制和实战场景三个维度,带大家彻底搞懂这个问题。
先给结论:在绝大多数MySQL场景下,用自增整型(INT/BIGINT)做主键比用UUID等字符串类型性能更好。这不是拍脑袋得出的结论,而是由InnoDB的B+树索引机制决定的。下面我们拆开揉碎了分析。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 存储引擎的底层逻辑
2.1 InnoDB的索引组织表特性
MySQL的InnoDB引擎采用索引组织表(IOT)结构,这意味着主键索引就是数据本身。与MyISAM不同,InnoDB的表数据实际上是按照主键顺序存储的。这种设计带来两个关键特性:
- 主键值会作为所有二级索引的"指针"
- 数据插入会直接影响物理存储顺序
举个例子,当我们用自增ID时,新数据总是追加到当前最大ID之后,不会导致页分裂。而用无序UUID时,新数据可能插入到任意位置,就像在字典中间插入新单词一样需要频繁调整页面。
2.2 B+树索引的工作原理
InnoDB使用B+树作为索引结构,这种数据结构有以下特点:
- 非叶子节点只存储键值和指针
- 所有数据都存储在叶子节点
- 叶子节点通过指针连接形成链表
当主键是自增整数时,B+树只需要在最右侧追加新节点。但使用UUID时,由于值随机分布,会导致:
- 频繁的页分裂(Page Split)
- 索引碎片化
- 缓存命中率下降
实测数据显示,UUID主键的表其索引大小通常是自增ID的2-3倍,这正是碎片化导致的。
3. 性能对比实测数据
3.1 插入性能测试
我做了组对比测试(MySQL 8.0,innodb_buffer_pool_size=1GB):
| 主键类型 | 插入10万条耗时 | 索引大小 |
|---|---|---|
| BIGINT自增 | 2.3秒 | 14MB |
| UUIDv4 | 8.7秒 | 37MB |
| UUIDv1 | 6.1秒 |
