MySQL 索引原理
索引(Index)是 MySQL 用来提高查询效率的数据结构。索引的核心原理是 通过减少数据扫描的范围,提高查询性能。索引类似于一本书的目录,可以加快查找的速度。
1. 索引的底层数据结构
MySQL 主要使用两种索引数据结构:
- B+ 树(B+Tree)索引(最常用)
- 哈希(Hash)索引
1.1 B+ 树索引
B+ 树是一种平衡多路搜索树,其特点:
B+ 树索引的优点
B+ 树索引的缺点
Hash 索引的优缺点
- 有序性:B+ 树索引存储的是有序的键值对,可以加速范围查询和排序操作。
- 磁盘友好:B+ 树的每个节点存储多个键值,减少磁盘 I/O。
- 所有数据存储在叶子节点,非叶子节点只存储索引,提高查询效率。
-
B+ 树索引的工作方式
假设有如下 SQL 语句:
-
SELECT * FROM users WHERE age = 25;
- MySQL 通过索引树的根节点开始查找,逐层查找对应的叶子节点。
- 叶子节点中存储了对应的数据行地址,然后通过该地址读取完整数据。
- 适用于单点查询(
=
)、范围查询(BETWEEN
、> <
)、排序查询(ORDER BY
)。 - 不适用于频繁变更的字段,因为增删改可能会引起索引重建,影响性能。
- 适用于大数据量查询,但索引维护会占用一定的存储空间。
- 由于 B+ 树有有序性,在范围查询和排序时可以避免额外的排序操作。
-
1.2 Hash 索引
Hash 索引基于 哈希表(Hash Table) 结构:
- 通过哈希函数计算键的哈希值,并存储到哈希表中。
- 查询时通过哈希值直接找到对应的存储位置。
优点 | 缺点 |
---|---|
适用于等值查询(= ) | 不支持范围查询(BETWEEN 、> 、< ) |
查询速度快(哈希查找 O(1)) | 无法支持 ORDER BY ,因为哈希值是无序的 |
适用于唯一键查询 | 发生哈希冲突时,查询效率下降 |
适用场景
- Memory 引擎默认使用 Hash 索引。
- 适用于等值查询,如
WHERE id = 100
,但不适用于范围查询。
2. 索引类型
MySQL 主要有以下几种索引:
索引类型 | 说明 | 适用场景 |
---|---|---|
主键索引(Primary Key) | B+ 树索引,唯一且非空 | 作为表的唯一标识 |
唯一索引(Unique Index) | B+ 树索引,保证列值唯一 | 需要唯一性约束的列(如邮箱、用户名) |
普通索引(Index) | B+ 树索引,不强制唯一 | 经常用于 WHERE 查询的字段 |
联合索引(Composite Index) | 由多个列组成的索引 | 适用于多列组合查询 |
全文索引(Full-Text Index) | 适用于文本搜索(InnoDB / MyISAM) | 搜索大段文本 |
哈希索引(Hash Index) | 哈希表结构,只适用于等值查询 | 仅用于 Memory 引擎 |
3. 聚簇索引和 非聚簇索引
在 MySQL 中,索引的存储方式决定了查询效率,其中聚簇索引和非聚簇索引是最核心的两种索引类型。
3.1. 聚簇索引(Clustered Index)
定义:
- 数据存储和索引放在一起,即 索引即数据,数据即索引。
- B+ 树的叶子节点直接存储整行数据,主键索引就是聚簇索引。
3.1.1 主要特点
- 存储顺序 = 索引顺序:数据按照 主键值 的顺序物理存储。
- 查询效率高:查找主键时,无需额外访问数据页。
- 范围查询快:因为数据是有序存储的,范围查询 (
BETWEEN
、> <
等) 非常高效。 - 表只能有一个聚簇索引:因为数据只能按一种方式物理存储。
3.1.2 MySQL 的实现
- InnoDB 存储引擎默认使用 主键作为聚簇索引。
- 如果没有主键,InnoDB 会选择一个
UNIQUE
索引 作为聚簇索引。 - 如果都没有,InnoDB 会自动创建一个隐藏的 rowid 作为聚簇索引。
3.2. 非聚簇索引(Non-Clustered Index)
定义:
- 索引存储与数据分开,索引存储的是 键值 + 指向数据行的地址(主键 ID)。
- 需要先查找索引,再通过索引找到对应的数据行,即 "回表查询"。
3.2.1 主要特点
- 索引和数据存储在不同的位置,索引只包含键值 + 记录指针。
- 非聚簇索引可以有多个,支持多列索引(如
email
、username
)。 - 查询时可能需要回表,即先通过索引查找主键,再回表查询完整数据。
3.2.2 MySQL 的实现
- InnoDB 的二级索引(普通索引、唯一索引等)都是 非聚簇索引。
- 二级索引存储的是主键值,而不是数据行的物理地址。
- 如果查询的是非主键字段,则需要回表查询。
特性 | 聚簇索引(Clustered Index) | 非聚簇索引(Non-Clustered Index) |
---|---|---|
存储方式 | 数据和索引存储在一起 | 数据和索引存储在不同的地方 |
索引叶子节点存储 | 完整数据行 | 主键 ID |
查询主键时 | 直接查找数据,速度快 | 需要回表查询,速度慢 |
范围查询 | 更快(数据顺序存储) | 较慢(数据不连续存储) |
索引个数 | 只能有一个 | 可以有多个 |
适用场景 | 主键查询、范围查询 | 非主键查询、联合索引 |