Skip to content

索引基础

没有索引的表,就像没有目录的书——你只能从第一页翻到最后一页来找一个词。


索引是什么

索引(Index) 是数据库中一种特殊的数据结构,用于加速数据检索。它类似于书籍的目录:你不需要逐页翻书,只需要看目录就能快速定位到目标内容。

在 MySQL 中,索引存储在独立的磁盘文件中(InnoDB 引擎下,索引和数据在同一个表空间文件),每个索引本质上是一棵 B+ 树。

一句话总结

索引 = 排好序的查找数据结构,用空间换时间。


索引为什么快

要理解索引为什么快,先看没有索引时数据库是怎么查数据的。

全表扫描:逐行查找

sql
SELECT * FROM orders WHERE customer_id = 10086;

没有索引时,MySQL 从第一行开始,一条一条地比较 customer_id 的值,直到找到匹配的记录或者遍历完所有行。

100 万条数据?最坏情况要比较 100 万次。

索引查找:二分定位

有了索引(假设是 B+ 树索引),查找过程是这样的:

  1. 从根节点开始,判断目标值在左子树还是右子树
  2. 逐层向下,直到叶子节点
  3. 在叶子节点中通过双向链表快速定位

100 万条数据,B+ 树高度约为 3~4 层,最多比较 3~4 次就能找到结果。

这就是索引快的本质:把全表扫描的 O(n) 降到了 O(log n)


索引的优缺点

索引不是银弹,它有代价。

优点

优点说明
加速查询减少 I/O 次数,显著降低查询时间
减少服务器扫描量不需要遍历全表
实现唯一约束唯一索引保证数据唯一性
支持排序和分组索引本身有序,减少 sort 操作

缺点

缺点说明
占用磁盘空间索引文件可能比数据文件还大
降低写操作性能INSERT/UPDATE/DELETE 时需要同步维护索引
增加维护成本数据变更时,索引需要实时更新
不是越多越好大量索引反而拖慢写入,浪费空间

索引设计的基本原则

不是所有字段都值得建索引,设计索引需要权衡。

适合建索引的字段

  • WHERE 子句中频繁使用的字段
  • JOIN 的 ON 条件涉及的字段
  • ORDER BY 和 GROUP BY 涉及的字段
  • 区分度高的字段( cardinality 高,如用户 ID)
  • 很少更新的字段(索引维护成本低)

不适合建索引的字段

  • 区分度很低的字段(如性别:只有男/女,区分度 50%)
  • 频繁更新的字段(每次更新都要维护索引)
  • 非常长的字符串字段(用前缀索引除外)
  • 查询中几乎不使用的字段(浪费空间)

索引设计经验法则

经验法则:为 WHERE、ORDER BY、GROUP BY 涉及的字段建索引。

一个经典的复合索引设计示例:

sql
-- 经常这样查询:
SELECT * FROM orders WHERE status = 'paid' ORDER BY created_at DESC;

-- 复合索引设计:
CREATE INDEX idx_status_created ON orders(status, created_at DESC);
--                    ↑ 等值查询放前  ↑ 排序字段紧随其后

这个索引同时覆盖了 WHERE 条件(status)和排序(created_at),查询时可以直接从索引中返回结果,无需回表。


MySQL 索引分类体系

从逻辑上,MySQL 索引分为以下几类:

分类角度类型
数据结构B+ 树索引、Hash 索引、R-Tree 索引(空间数据)
物理存储聚簇索引(主键索引)、二级索引(非主键索引)
字段个数单列索引、联合索引(复合索引)
唯一性唯一索引、普通索引

关于各种索引类型的详细讲解,参见 索引类型:聚簇/二级/联合/B+树/Hash


验证索引效果

EXPLAIN 可以看到查询是否使用了索引:

sql
-- 查看查询计划
EXPLAIN SELECT * FROM orders WHERE customer_id = 10086;

关键字段说明:

字段含义
typeALL全表扫描,慢
typeref, range索引扫描,快
keyidx_xxx实际使用的索引名
rows1000000预计扫描行数

详细内容见 EXPLAIN 全字段剖析


小结

索引是 MySQL 性能优化的核心。理解索引的原理和设计原则,比记住几条优化技巧更重要。

记住三句话:

  • 索引用空间换时间:磁盘空间换查询速度
  • 索引是排好序的 B+ 树:有序才能二分查找
  • 索引不是越多越好:写入变慢,空间膨胀

下一步

索引的底层数据结构是什么?聚簇索引和二级索引有什么区别?

索引类型 继续。

基于 VitePress 构建