MySQL 索引原理

2 阅读4分钟

MySQL 索引本质是为了快速查找数据而设计的排序列表,就像书籍的目录——不用翻完整本书,看目录就能直接定位页码,大幅减少查询耗时。

我从底层结构、工作原理、类型、优缺点讲,让新手也能完全理解。


一、核心:索引的底层数据结构

MySQL 索引默认使用 B+ 树(InnoDB 存储引擎),这是索引高效的核心原因。

1. 为什么不用哈希/二叉树?

  • 哈希索引:等值查询极快,但无法范围查询(如 where id > 100),不适合业务场景;
  • 普通二叉树:数据有序时会变成链表,查询退化为全表扫描;
  • B 树:节点存数据,范围查询需要遍历整棵树,效率低。

2. B+ 树的核心优势(索引的灵魂)

  1. 多路平衡:树高极低(千万级数据仅 3-4 层),查询速度稳定;
  2. 叶子节点相连:所有数据存在叶子节点,且用双向链表串联;
  3. 非叶子节点只存键值:占用空间极小,能全部加载到内存,避免磁盘IO。

一句话总结:B+ 树让 MySQL 无论查询、范围查询、排序、分页,都能做到最少磁盘IO、最快速度


二、InnoDB 索引的两种核心类型

InnoDB 是 MySQL 默认引擎,索引和数据存在同一个文件,分为两类:

1. 聚簇索引(Clustered Index)

  • 定义主键索引就是聚簇索引,数据直接存放在索引的叶子节点上;
  • 特点
    1. 一张表只有一个聚簇索引;
    2. 数据物理存储顺序和索引顺序一致;
    3. 查询速度最快(直接在索引上拿到完整数据)。
  • 无主键时:InnoDB 会自动生成隐藏列作为主键。

2. 二级索引(普通索引/联合索引)

  • 定义:除主键外的所有索引(普通索引、唯一索引、联合索引);
  • 结构:叶子节点不存完整数据,只存主键值
  • 查询流程
    1. 先查二级索引 → 找到对应主键;
    2. 再用主键查聚簇索引 → 拿到完整数据(这个过程叫回表)。

三、索引工作原理:查询时发生了什么?

举个例子:SELECT * FROM user WHERE id = 100;

  1. 加载 B+ 树的根节点到内存;
  2. 比较键值,判断数据在左子树还是右子树;
  3. 逐层向下查找,只访问 3-4 个节点
  4. 定位到叶子节点,直接读取数据。

无索引:全表扫描(逐行遍历,千万数据秒级响应) ✅ 有索引:B+ 树查找(毫秒级响应)


四、最左前缀原则(联合索引核心原理)

联合索引 (a, b, c) 本质是按 a 排序 → a 相同按 b 排序 → b 相同按 c 排序的 B+ 树。

生效规则

  • where a=1 → 生效
  • where a=1 and b=2 → 生效
  • where a=1 and b=2 and c=3 → 生效
  • where b=2 → 失效(跳过 a,无法确定范围)
  • where a=1 and c=3 → 仅 a 生效(b 断档,c 无法排序匹配)

五、索引的两大关键特性

1. 覆盖索引

查询的字段,全部在索引里,不需要回表,速度极快。 例:索引 (name, age),查询 SELECT name, age FROM user WHERE name = "张三" → 直接从索引拿数据,无回表

2. 索引失效(高频坑点)

这些操作会让索引直接报废:

  • 使用函数/运算:where YEAR(create_time) = 2024
  • 隐式类型转换:where id = "123"(字符串=数字)
  • 模糊查询以 % 开头:where name like "%张三"
  • 使用 != / is null / or(无索引覆盖时)

六、索引的优缺点(必须知道)

✅ 优点

  1. 大幅提升查询、排序、分组速度;
  2. 减少服务器扫描的数据量;
  3. 避免使用临时表、文件排序。

❌ 缺点

  1. 占用磁盘空间(索引也是数据);
  2. 增删改变慢(数据变化时,B+ 树需要重新平衡);
  3. 过多索引会让优化器选择困难,降低效率。

七、极简总结(核心记忆点)

  1. 索引 = B+ 树结构 = 排序列表,目的是减少磁盘IO;
  2. 聚簇索引(主键):叶子节点存完整数据,最快;
  3. 二级索引:叶子节点存主键,查询需要回表;
  4. 联合索引:遵循最左前缀原则;
  5. 覆盖索引:避免回表,性能最优;
  6. 索引能加速查询,但会拖慢写入,不能滥用。

总结

  1. MySQL 索引底层是 B+ 树,这是高效查询的核心;
  2. 主键索引是聚簇索引,数据直接存在索引上;
  3. 联合索引必须遵守最左前缀原则
  4. 合理使用覆盖索引,避免回表和索引失效。