Skip to content

敖丙系列--我以为自己对索引很了解,直到我遇到了阿里面试官 ​

看在前面 ​

  • 原文:敖丙,掘金 (原链已失效 2026-10,掘金文章已删除) 。整理时掘金原文与知乎镜像均已 404。本篇依据主题与可考的原文片段重写。可考的面试问题清单包括:索引有哪些数据类型、索引是怎样的结构、哪些字段适合建索引。还有 B+ 的优点、聚合与非聚合索引的区别、为什么索引降低增删改性能、select * 与回表、覆盖索引。
  • 本文是敖丙系列数据库篇的索引专题,以"阿里面试官连环追问"为主线。索引失效场景见库内《数据库索引失效总结》,更系统的索引原理见《数据库两大神器之索引》。

一、索引是什么 ​

  • 索引是帮助 MySQL 高效获取数据的、排好序的数据结构。两个关键词:排好序(支撑范围查找)、数据结构(不只是"目录"的比喻)。

  • InnoDB 默认使用 B+ 树索引;Memory 引擎默认 Hash 索引;此外还有全文索引等。

二、为什么是 B+ 树:候选结构逐一淘汰 ​

2.1 哈希表:等值快,范围歇菜 ​

  • 把键 hash 后散列到桶里,等值查询 O(1)。但数据无序,无法支持范围查询(between、>、order by 都要全表扫)。也无法利用索引排序、不支持最左前缀,哈希碰撞多时效率下降。只适合 KV 型等值场景(Memory 引擎、自适应哈希索引)。

2.2 二叉搜索树 / 红黑树:太"瘦高" ​

  • 二叉树插入有序数据会退化成链表。红黑树能自平衡,但仍是二叉——每个节点只有两个分叉,千万数据树高 20+ 层。磁盘 IO 次数 = 树高,代价太大。

  • 索引的查询瓶颈在磁盘 IO,结构越"矮胖"越好——于是要用多叉树(B 树/B+ 树)。

2.3 B 树:非叶子节点也存数据 ​

  • B 树是多路平衡查找树,每个节点既存键也存整行数据。问题:数据行很大,一页 16 KB 装不了几条,扇出变小、树变高。且范围查询要在树里中序回旋反复上下走。

2.4 B+ 树胜出的两个理由 ​

  • 非叶子节点只存键值(索引列)不存数据,单页 16 KB 能放上千个键。扇出极大、树极矮(3 层撑千万级),一次查询 = 树高次页 IO。

  • 叶子节点存全部数据且用双向链表相连,范围查询、排序只需顺着链表顺序扫,不用回到树上。

三、一棵 B+ 树能存多少数据(经典推导) ​

  • InnoDB 页大小默认 16 KB;主键假设 bigint(8 B)+ InnoDB 后继指针(6 B)= 每个索引项约 14 B。

  • 非叶子节点一页可放:16384 ÷ 14 ≈ 1170 个索引项。

  • 叶子节点假设每行数据 1 KB,一页放 16 行。

  • 树高 3 层的容量:1170 × 1170 × 16 ≈ 2190 万行。这就是"三层 B+ 树支撑约 2000 万数据、一次主键查询最多 3 次页 IO"的由来。也是很多公司把单表 2000 万作为分库分表参考线的原因。

四、聚簇索引与非聚簇索引:回表的来源 ​

  • 聚簇索引(主键索引):叶子节点存整行数据,"数据即索引、索引即数据"。InnoDB 表本身就是按主键组织的 B+ 树。

  • 非聚簇索引(二级/辅助索引):叶子节点存主键值而不是整行数据。

  • 回表:走二级索引先查到主键值,再回到聚簇索引树上把整行数据查出来——多一次树查找。select * from t where name = 'x'(name 上有普通索引)就是典型的两次查找。

  • 推论:能走主键就走主键;二级索引查到的主键越无序,回表时聚簇树上的随机 IO 越多。

五、覆盖索引:让查询不回表 ​

  • 如果查询的列全部包含在索引里,就不需要回表——这就是覆盖索引。刚才 select * 要回表。如果只查 ID,name 索引的叶子节点上本来就有(二级索引叶子存主键),一次树查找就完事。

  • 实战写法:把 select 的列收窄、或建立包含所需列的联合索引,explain 的 Extra 出现 Using index 即命中覆盖索引。

六、哪些字段适合建索引 / 为什么索引拖慢增删改 ​

  • 适合:WHERE / ORDER BY / JOIN 条件里高频出现的列;区分度高(基数/行数接近 1)的列; NOT NULL 的列。

  • 不适合:表很小、频繁增删改、区分度低(性别、状态标志)、极少作为查询条件的列。

  • 为什么索引会降低插入、删除、修改的性能:表的每个索引都是一棵独立的 B+ 树。DML 不仅要改数据页,还要同步维护所有索引树。插入可能引发页分裂、删除留空洞、修改键要挪节点。这也是"索引不是越多越好"的原因。

七、面试主线小结 ​

  • 一条追问链自检。索引是什么(有序数据结构)→ 为什么 B+ 树(对比 Hash/红黑树/B 树,矮胖 + 链表)。能存多少数据(16 KB / 1170 / 3 层 2000 万)→ 聚簇与非聚簇(叶子存整行 vs 存主键)。回表(二级索引回聚簇树)→ 覆盖索引(不回表)→ 为什么 DML 变慢(每棵索引树都要维护)。

原链接已失效,2026-10 依据主题重写。