深蓝黑背景品牌封面:右侧大标题「主键用 int 还是 string」,副标题「不只是存储大小问题」;左侧原创装饰——两棵迷你 B+ 树并排,左树节点整齐右倾、分支均匀寓意自增 int 的紧凑有序,右树节点散布、分支歪斜寓意随机字符串主键带来的页分裂与碎片;左上标注「经典题解析 · 数据库」,右上标注「Day 10 · 10-18」 图 1:本文封面,两棵 B+ 树的形态差异,就是两种主键的代价差异。

先说明属性:这是一篇经典题解析,题目出自本地历史面试资料(原题问「使用 int 做 primary key 和使用 string 有什么优劣」),与任何公司的当前招聘无关。它常被当成「存储省几个字节」的小题,实际上主键选型牵动聚簇索引布局、写入热点和分布式 ID,是表设计的第一决策。

想象面试现场:「主键用 int 还是 string?」——只答「int 省空间」的人,马上会被追问「还有呢」。

核心结论一句话

按四个维度取舍。存储与索引:int 每个键 4 到 8 字节,string 动辄几十字节,且 InnoDB 的二级索引每条记录都回存主键值,主键越长,全表所有二级索引跟着膨胀。写入路径:自增 int 永远追加到最右页,顺序写、无分裂;随机字符串落点分散,页分裂与碎片随之而来。有序性:自增主键即时间序,按主键扫就是按时间扫;随机串无序。分布式:自增跨库会撞号,需要号段或发号器;随机串天然全局唯一、可离线生成。一句话选型:单库高写入选自增 int,多库分片或需要离线造号选可排序的 string 族。

为什么主键长度会被放大?聚簇索引的结构决定的。

InnoDB 的表数据就存在聚簇索引这棵 B+ 树的叶子页里,聚簇索引通常就是主键。关键在于二级索引的设计:每条二级索引记录里除了索引列本身,还存着该行的主键值,用来回到聚簇索引找到整行。官方文档说得很直白——主键长,二级索引就占更多空间,所以主键短是有利的。一张表有五六个二级索引时,36 字节的 UUID 字符串对比 8 字节的 bigint,索引体积差出好几倍。还有个附带事实:完全不设主键时,InnoDB 会生成一个隐藏的聚簇索引,靠 6 字节单调递增的行 ID 撑起来——主键不是可选题,只是你选还是它替你选。

写入路径:顺序追加与随机插入的差距。

自增主键的每一次插入都落在 B+ 树最右端的页上,页写满开新页,是纯粹的顺序追加。随机字符串主键的落点散布在整棵树各处:目标页可能不在内存里要先读进来,页满了还要分裂搬数据,写放大与碎片都来了。高写入场景下,这个差距直接决定 TPS 的天花板。

有序性是容易被忽略的赠品。 自增主键单调递增,天然就是时间序:按主键倒序翻页就是按创建时间翻页,范围扫描有明确意义。随机串主键没有这层语义,想要时间序得另加索引,索引又要回存主键值,膨胀的账再算一遍。

分布式场景是 string 族的主场。 分库分表之后,各库的自增序列会撞号,要么按库分段、要么引入发号器,都多出一块基础设施。随机串可以离线生成、天然全局唯一。如果既要全局唯一又想要有序性,ULID 这类方案把时间戳放在开头:48 位毫秒时间戳加 80 位随机数,编码成 26 个字符,字典序可排——它比纯随机 UUID 对 B+ 树友好得多,但长度代价依然比 int 大。

四维对比图:以一条中轴分为左右两列,左列 int 自增、右列 string 随机串。第一维存储与索引——int 每键 4 到 8 字节,聚簇索引小而紧;string 每键几十字节,主键值还会被所有二级索引的叶子回存,索引整体膨胀。第二维写入路径——自增永远追加到最右页,顺序写、无分裂;随机串落点分散,页分裂与碎片随之而来。第三维有序性——自增主键即时间序,按主键扫就是按时间扫;随机串无序,范围扫描失去意义。第四维分布式——自增跨库会撞号,需要号段或发号器;随机串天然全局唯一、可离线生成。底部结论:单库高写入选自增 int,多库分片或需要离线造号选 string 族(UUID/ULID),纠结时看写入热点与索引体积两笔账 图 2:四维取舍对照,纠结时看写入热点与索引体积两笔账。

可能的追问与易错点。「UUID 想当主键怎么办?」至少要换成时间戳开头的可排序变体,纯随机的 UUID 直接当主键等于主动选择页分裂。「int 够用吗?」int 约 21 亿上限,流水大表直接用 bigint,别给未来埋雷。「业务字段能不能当主键?」能,但要满足稳定不变;订单号之类带业务含义的串当主键,等于把长度与变更风险一起扛上。易错点有二:一是只算存储的小账,漏算二级索引回存放大这笔大账;二是分库分表之后还想沿用单库自增,撞号问题在上数据迁移那天集中爆发。AI 业务里会话 ID、样本 ID 每天都在面对这道选择题:推理网关内部流水用自增 bigint,对外暴露、离线生成的标识用可排序字符串族,各取所长。

给你的练习:挑一张你最熟的表,数一数它有几个二级索引,把主键长度乘上索引个数,估一下换成 36 字节字符串主键会多花多少存储。账算出来,选型就不再是口味之争。你的项目主键用的是哪种?踩过撞号或页分裂的坑吗?欢迎分享。