MySQL 索引面试内容汇总

6 阅读4分钟

1. B+Tree 是 MySQL 中最核心的索引结构

B+Tree 结构特点

  • 多叉平衡树;
  • 所有数据都在 叶子节点;
  • 叶子节点之间 按顺序链表连接;
  • 非叶子节点只存 索引键 + 指针

为什么 MySQL 用 B+Tree:

  • 磁盘 IO 次数少 , B+Tree 高度很低;
  • 非常适合范围查询 , 因为叶子节点有 链表
  • 支持排序, 因为叶子节点 天然有序
  • 支持最左前缀匹配

2. B+Tree 与 Hash 索引的区别

Hash 索引特点

  • 优点
    • 查询速度非常快
    • 等值查询极佳
  • 缺点
    • 不支持范围查询
    • 不支持排序
    • 不支持最左匹配

InnoDB 的自适应 Hash

  • InnoDB 会自动把 热点 B+Tree 查询转为 Hash
  • Adaptive Hash Index (AHI)

3. MySQL 索引底层

MySQL 索引底层:

B+Tree Hash R-Tree

但 生产环境 95% 都是 B+Tree。

原因:

B+Tree 同时支持

等值查询 范围查询 排序 索引扫描

MySQL索引底层主要使用 B+Tree、Hash、R-Tree 三种数据结构,其中 B+Tree 是最核心的实现,InnoDB 和 MyISAM 的普通索引与主键索引基本都是 B+Tree;Hash 索引用于 Memory 引擎和 InnoDB 的自适应 Hash;R-Tree 用于 GIS 空间索引。

4. 为什么 MySQL 选择 B+Tree 而不是红黑树

索引选择 B+Tree 而不是 红黑树,核心原因是:数据库索引主要面对磁盘 IO,而不是纯内存操作。B+Tree 在 磁盘访问模式、范围查询、树高度控制 等方面明显更适合数据库场景。

数据库索引设计必须优化三个关键指标:

  • 1️⃣ 减少磁盘 IO
  • 2️⃣ 支持范围查询
  • 3️⃣ 支持排序扫描

所以数据库设计目标是:尽量减少树的高度,从而减少磁盘访问次数

数据库读取数据是 按页(Page)读取。在 InnoDB 中:Page Size = 16KB ; B+Tree 节点 刚好就是一个 Page。 例如:16KB / 16B ≈ 1000 个 key; 所以一个节点可以存:≈1000 个索引 而红黑树:一个节点只存一个 key; 导致:大量磁盘 IO 浪费

红黑树结构:中序遍历才能获得有序数据; 需要 频繁跳跃访问节点。磁盘访问效率非常差。

MySQL 选择 B+Tree 而不是红黑树的主要原因是数据库索引需要减少磁盘 IO。红黑树是二叉结构,树高度较高,查询时需要多次磁盘访问;而 B+Tree 是多路平衡树,一个节点可以存储大量 key,使树高度非常低,通常 3~4 层即可存储上亿数据,从而大幅减少磁盘 IO。同时 B+Tree 的叶子节点通过链表连接,非常适合范围查询和排序扫描,因此数据库索引普遍采用 B+Tree 结构。

5. B-Tree 与 B+Tree 的结构区别

B-Tree 的特点:

  • 所有节点都存储 key 和数据
  • 每个节点都可能是最终数据节点
  • 查找可能在任意层结束

B+Tree 的特点:

  • 非叶子节点只存 key
  • 数据全部在叶子节点
  • 叶子节点之间有链表

MySQL 选择 B+Tree 而不是 B-Tree 的主要原因是 B+Tree 更适合数据库的磁盘访问模式。B+Tree 的内部节点只存储 key 和指针,使得每个节点可以存储更多 key,从而降低树的高度,减少磁盘 IO。同时 B+Tree 的所有数据都在叶子节点,并且叶子节点通过链表连接,非常适合范围查询和顺序扫描。因此数据库系统普遍采用 B+Tree 作为索引结构。

6. 聚簇索引

聚簇索引是指 索引结构和数据行存储在一起,也就是说 B+Tree 的叶子节点直接存储整行数据

在 InnoDB 中:主键索引就是聚簇索引

表的数据 按照主键顺序存储在 B+Tree 中 换句话说:索引 = 数据 而不是:索引 → 指向数据

聚簇索引的叶子节点就是数据页

聚簇(Clustered)”的含义是:数据行按索引顺序聚集在一起


除了主键索引,还有:

  • 普通索引
  • 唯一索引
  • 联合索引

这些叫:Secondary Index(二级索引)

二级索引的叶子节点存什么? 在 InnoDB 中:二级索引叶子节点存储的是:索引列 + 主键值 而不是:索引列 + 数据地址

一张表只能有一个聚簇索引,因为:数据只能按一种顺序存储

在 InnoDB 存储引擎中,一张表只能有一个聚簇索引。聚簇索引通常是主键索引,如果表没有主键,则会选择第一个 UNIQUE NOT NULL 索引作为聚簇索引;如果也没有这样的索引,InnoDB 会自动生成一个隐藏的 6 字节 row_id 作为聚簇索引。MySQL 不能直接创建聚簇索引,通常是通过定义 PRIMARY KEY 来设置聚簇索引。