一、为什么是 B+树
索引的本质是"用空间换时间",让查找不用全表扫。能加速查找的结构很多,MySQL 选 B+树,原因就三点:
- 矮胖
:一个节点能放很多 key(默认 16K 页),三层就能存千万级数据,查找只要约 3 次磁盘 IO。 - 叶子成链
:所有数据都在叶子节点,且用双向链表串起来,范围查询顺着链表走就行,不用回树里绕。 - 非叶子只存 key
:把更多 key 塞进节点,树更矮,IO 更少。对比之下,B 树数据分散在各层、Hash 不支持范围、红黑树太高(IO 多)。
一句话:B+树 = 矮(少 IO)+ 叶子链表(好范围)。
二、聚簇索引长什么样
InnoDB 里,表数据本身就是按主键组织的 B+树,叫聚簇索引:非叶子节点存「主键值 + 指针」,叶子节点存整行数据。
没建主键时,InnoDB 会挑唯一列;再没有就隐式生成 row_id。所以主键索引叶子直接是数据,这也是"主键查询最快"的原因。
二级索引(普通/联合索引)是另一棵 B+树:叶子节点存「索引列值 + 主键值」,不是整行。记住这点,才能理解下面的"回表"。
三、最左前缀原则
联合索引 (a, b, c) 在 B+树里按 a→b→c 顺序排序,像电话簿:先按姓、同姓按名。
能命中:
WHERE a=1WHERE a=1 AND b=2WHERE a=1 AND b=2 AND c=3
跳最左就废:
WHERE b=2❌没 a,只能全扫 WHERE a=1 AND c=3⚠️只用上 a,c 失效(跳过 b)
口诀:最左前缀 = 从左边连续匹配,断了后面失效。 补充:范围查询(>、<、LIKE 'abc%')能命中,但它后面的列用不上索引,如 a=1 AND b>2 AND c=3 里 c 失效。
四、回表与覆盖索引
二级索引叶子只存主键,当查询需要索引列以外的字段时,InnoDB 要拿主键回聚簇索引再查一次整行——这就是回表。
-- 有联合索引 (name, age) SELECT * FROM user WHERE name='张三'; -- 找到主键后回表取全部字段
只查索引里就有的列,不用回表:
SELECT name, age FROM user WHERE name='张三'; -- name、age 都在索引里 → 覆盖索引,直接返回
"索引已包含查询所需全部字段"叫覆盖索引,省一次回表更快。所以尽量少写 SELECT *,要哪些列查哪些,更容易命中覆盖索引。
五、面试速记
- 为什么 B+树?
矮(少 IO)+ 叶子链表(好范围);Hash 不支持范围,红黑树太高。 - 聚簇索引
叶子存整行,二级索引叶子存「索引值 + 主键」。 - 最左前缀
:从左边连续匹配,断了失效;范围查询后列失效。 - 回表
:二级索引查非索引列需回主键索引再查一次。 - 覆盖索引
:查询列都在索引里,不回表更快;少写 SELECT *。 - 主键用自增整型最好
:顺序追加,页分裂少,索引更紧凑。
六、一句话带走
B+树靠"矮 + 叶子链表"把查询打到 3 次 IO 内;联合索引守最左前缀;二级索引查整行会回表,用覆盖索引避开。讲清这三句,索引面试就过了。
MySQL索引面试
下一篇预告:Buffer Pool 是怎么把查询再快一个量级的。

