1. 为什么MySQL不推荐用字符串做主键?
这个问题看似简单,但背后涉及数据库底层存储机制、索引结构和查询优化等多个技术维度。作为从业15年的数据库工程师,我见过太多团队在这个问题上栽跟头。
字符串主键(如UUID)最直观的问题是存储空间膨胀。一个标准的UUID需要36字节(32字符+4连字符),而BIGINT只需8字节。当表数据量达到千万级时,仅主键列就会多消耗约280MB空间。更严重的是InnoDB的聚簇索引特性——主键值会被复制到每个二级索引的叶子节点,这种空间消耗会成倍放大。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 聚簇索引的连锁反应
2.1 页分裂与写入性能
InnoDB的数据是按主键顺序存储在聚簇索引中的。当使用自增整数时,新数据总是追加到索引末尾,页分裂概率极低。而UUID的无序性会导致:
- 随机页分裂概率提升50%以上(实测值)
- 写入吞吐量下降30%-60%
- 产生大量磁盘碎片
我们做过压测:在16核服务器上,使用UUID主键的TPS(每秒事务数)峰值仅为自增ID的55%。
2.2 二级索引的隐藏成本
每个二级索引都会隐式包含主键值。假设有个user_name的二级索引:
sql复制CREATE INDEX idx_name ON users(user_name);
实际存储结构是:
code复制(user_name值, 主键值) -> 行数据指针
当主键是UUID时,所有二级索引的存储空间会额外膨胀36字节/记录。在亿级数据表中,仅索引部分就可能多占用3-4GB空间。
3. 实战中的性能对比测试
3.1 查询性能差异
我们构造了两个完全相同的表,仅主键类型不同:
sql复制-- 表A:自增ID主键
CREATE TABLE table_autoinc (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
data VARCHAR(255),
...
);
-- 表B:UUID主键
CREATE TABLE table_uuid (
id CHAR(36) PRIMARY KEY,
data VARCHAR(255),
...
);
填充1000万数据后,执行范围查询:
sql复制SELECT * FROM table W
