图 1:本文封面,点明题目与三个关键词。
先说明属性:这是一篇经典题解析,题目出自本地历史面试资料(见文末来源说明),与任何公司的当前招聘无关。
想象面试现场,面试官问:「从 InnoDB 的索引结构看,索引 key 为什么不能太长?」不少人只答得出「太长会报错」,追问一句「为什么」就卡住了。这道题的分水岭在于:能不能从存储结构推出结论,而不是背结论。
第一步,审题。
考察点有两层:懂不懂 B+ 树索引在磁盘上如何组织;能不能从结构推出工程约束,包括那几个长度上限数字。按「结构—推理—数字」的顺序答,比直接背数字稳。
第二步,基础回答:三层原因。
其一,页大小固定,key 越长扇出越低。InnoDB 的索引组织成 B+ 树:内部页只存「key 加子页指针」,数据行都在叶子页,叶子页之间用链表相连。页的默认大小是 16KB,一页能容纳的 key 数约等于页容量除以单个 key 的大小。key 越长,单页存放的 key 越少,扇出(每个节点拥有的子节点数)越低;同样的数据量下,扇出越低树就越高。B+ 树每增高一层,一次点查询就要多读一个页——页不在内存里,就是一次磁盘 IO。控制 key 长度,本质是在控制树高与 IO 次数。
其二,官方文档给了硬数字。MySQL 文档写明:DYNAMIC 或 COMPRESSED 行格式下,索引 key 前缀长度上限为 3072 字节;REDUNDANT 或 COMPACT 行格式下只有 767 字节,超限直接报错。文档还举例:utf8mb4 每字符最多占 4 字节,TEXT 或 VARCHAR 列上超过 191 个字符的列前缀索引就会撞上 767 字节的限制。如果建实例时把页缩到 8KB 或 4KB,上限也按比例降为 1536 或 768 字节——限制不是拍脑袋的规定,而是随页结构走的。
其三,长主键会放大所有二级索引。官方文档明确:二级索引的每条记录都包含主键列,InnoDB 靠这个主键值回查聚簇索引。主键如果选了个长字符串,每一棵二级索引树的每一条记录都要背着它——同样的索引要占更多页,内存里放得下的索引页更少。所以文档建议主键尽量短。
图 2:从页大小到扇出、树高再到 IO 次数的完整推理链。
第三步,可能的追问。
「行本身有大小限制吗?」有:默认 16KB 页下,行大小上限略小于半页,约 8000 字节;超长的变长列会被选择性地挪到页外存储。「表没定义主键会怎样?」InnoDB 会生成隐藏的聚簇索引 GEN_CLUST_INDEX,建在单调递增的 6 字节 row ID 上。「key 多短算合适?」能用整型就别用长字符串;必须索引长文本就用前缀索引,并接受选择性下降的代价。「还有哪些相关限制?」同一份文档还给出:一张表最多 64 个二级索引、联合索引最多 16 列。索引不是免费资源,每个二级索引都是一棵要随写入维护的 B+ 树,这本身也回答了「为什么不能什么都建索引」。
第四步,工程应用与 AI 关联。
「固定预算下,单个条目越大,单页条目越少,层级越深」这条推理链是存储系统的通用直觉。AI 应用要存储和检索海量向量与元数据,特征库、样本库底层仍是索引结构;向量索引 IVF 和 HNSW 面对的是同款权衡——内存预算固定时,分区粒度或图的度决定一次查询要访问多少数据块。看懂 InnoDB 的取舍,再理解向量索引的设计会顺很多。
易错点清单。
一,把 3072 说成字符数——单位是字节,utf8mb4 下要除以 4。二,以为上限是任意规定——它由页大小推导,页缩水上限同步降。三,只想到聚簇索引,漏掉主键长度对全部二级索引的放大效应。四,过度承诺「key 短一定更快」——树高相同(同为三层)时差距有限,要落到具体行数与扇出上谈。
回到面试现场,建议的答题节奏:先讲 B+ 树结构,再走「页固定、key 定扇出、扇出定树高、树高定 IO」的推理链,然后报官方上限数字,最后补二级索引放大效应。结构与数字互相印证,这题就答完整了。
如果面试官追问「既然 key 越短越好,为什么实际表里还有那么多长字符串索引」,你会从哪些角度回应?欢迎写出你的答案。
参考资料
- InnoDB Limits(MySQL 8.4 官方文档:索引 key 前缀上限 3072 字节(DYNAMIC/COMPRESSED)与 767 字节(REDUNDANT/COMPACT)、utf8mb4 下 191 字符示例、页缩至 8KB/4KB 上限降为 1536/768、默认 16KB 页下行上限约 8000 字节与页外存储、每表最多 64 个二级索引、联合索引最多 16 列) — https://dev.mysql.com/doc/refman/8.4/en/innodb-limits.html
- The Physical Structure of an InnoDB Index / Clustered and Secondary Indexes(MySQL 8.4 官方文档:聚簇索引即主键、二级索引记录包含主键列、主键长则二级索引更占空间、无主键时生成 6 字节 row ID 上的 GEN_CLUST_INDEX) — https://dev.mysql.com/doc/refman/8.4/en/innodb-index-types.html