# MySQL 的索引类型有哪些?

12 min read
Table of Contents

MySQL 的索引类型有哪些?

MySQL 索引类型详解

【核心定义】

MySQL 索引是一种帮助存储引擎高效获取数据的排好序的数据结构,它通过减少磁盘 I/O 次数来加速数据检索。

【关键要点】

  1. 按数据结构分类

    • B+Tree 索引:MySQL 默认且最常用的索引类型,适用于全值匹配、范围查询和排序操作。
    • Hash 索引:基于哈希表实现,仅支持等值查询(=, IN),不支持范围查询和排序,Memory 引擎默认使用。
    • R-Tree(空间索引):用于地理空间数据类型(如 GEOMETRY),支持空间关系查询。
    • Full-Text(全文索引):基于倒排索引实现,用于全文搜索,支持 MATCH AGAINST 操作。
  2. 按物理存储分类

    • 聚簇索引(Clustered Index):InnoDB 中,表数据文件本身就是按 B+Tree 组织的一个索引结构,叶子节点存储完整的行数据。一张表只有一个聚簇索引。
    • 非聚簇索引(Secondary Index / 辅助索引):叶子节点存储的是主键值(InnoDB)或行数据的物理地址(MyISAM)。查询时需要回表。
  3. 按字段特性与数量分类

    • 主键索引(PRIMARY KEY):特殊的唯一索引,不允许 NULL 值。InnoDB 中它就是聚簇索引。
    • 唯一索引(UNIQUE KEY):保证索引列的值唯一,允许 NULL 值(但最多一个 NULL)。
    • 普通索引(INDEX / KEY):最基本的索引,无任何约束。
    • 联合索引(复合索引):在多个列上建立的索引。遵循最左前缀匹配原则。
  4. 按数据存储方式分类(InnoDB 特有)

    • 聚集索引:即聚簇索引。
    • 二级索引:即非聚簇索引,包括唯一索引、普通索引、联合索引。

【深度推导/细节】

1. B+Tree 为何是 MySQL 索引的默认选择?

  • 对比 B-Tree:B+Tree 非叶子节点只存键值,不存数据,因此单次 I/O 能加载更多索引键,树的高度更低。所有数据都存储在叶子节点,且叶子节点间有双向链表连接,范围查询和顺序访问效率极高。
  • 对比 Hash:Hash 索引虽等值查询 O(1),但无法支持 >、<、BETWEEN 等范围查询,也无法利用索引排序。且哈希冲突处理(拉链法)在数据量大时可能退化。
  • 磁盘 I/O 优化:B+Tree 的扇出性高,3-4 层即可存储亿级数据,将随机 I/O 转为顺序 I/O(通过叶子节点链表)。

2. 联合索引的最左前缀原则与索引下推(ICP)

  • 最左前缀原则:对于索引 (a, b, c),查询条件必须包含 a 才能使用该索引。有效组合:(a), (a, b), (a, b, c)。
  • 索引下推(ICP, MySQL 5.6+):在联合索引查询时,存储引擎层会先根据索引中包含的字段进行过滤(即使该字段不能用于索引查找),再将结果返回给 Server 层,减少回表次数。
    • 示例:WHERE a = 1 AND b LIKE ‘%abc’,在 ICP 开启后,引擎会在索引中同时判断 a=1 和 b LIKE ‘%abc’,而不是只判断 a=1 就回表。

3. 覆盖索引与回表查询

  • 覆盖索引:查询的字段全部包含在某个索引中,引擎无需回表即可返回结果,性能极高。
    • 优化策略:高频查询尽量设计为覆盖索引,或使用联合索引“覆盖”更多字段。
  • 回表查询:当使用二级索引查询时,若所需字段不在索引中,需要根据叶子节点存储的主键 ID 回到聚簇索引中查找完整行数据。这是主要的性能瓶颈之一。

【关联/对比】

特性InnoDB 索引MyISAM 索引
索引类型聚簇索引 + 二级索引非聚簇索引(索引和数据文件分离)
文件存储.ibd 文件存储索引和数据.MYI 文件存索引,.MYD 文件存数据
叶子节点内容聚簇索引存行数据,二级索引存主键值存指向数据行的物理地址(偏移量)
事务支持支持不支持

与 MongoDB 索引对比:MongoDB 默认使用 B-Tree,但也支持哈希、地理空间等索引。其“覆盖查询”概念与 MySQL 类似,但数据结构更灵活(文档模型)。

『面试官追问』

  1. 为什么 InnoDB 表必须有且只有一个聚簇索引?

    • 因为数据本身只能按一种物理顺序存储。如果未定义主键,InnoDB 会选择一个唯一的非空索引代替,若没有,则会隐式创建一个 6 字节的 ROWID 作为聚簇索引。
  2. Hash 索引在哪些场景下可能比 B+Tree 快?为什么不用它做默认索引?

    • 场景:纯等值查询且数据离散度高、不涉及排序和范围查询时(如缓存表)。
    • 原因:如前所述,其无法支持数据库最常用的范围查询和排序操作,且不支持部分索引键查询(联合索引必须全键匹配)。Memory 引擎支持。
  3. 什么是自适应哈希索引(AHI)?

    • InnoDB 的内部优化机制。当监测到某些索引值被非常频繁地访问时,会在内存的 Buffer Pool 中为其建立一个哈希索引,从而将 B+Tree 的 O(log n) 查询优化为 O(1)。此过程对用户完全透明。
  4. 全文索引底层是怎么实现的?和 LIKE 模糊查询有什么区别?

    • 实现:基于倒排索引。它会提取文本中的关键词(分词),并记录每个关键词在哪些文档中出现以及位置。
    • 区别:LIKE ‘%keyword%’ 会导致全表扫描,效率极低。全文索引通过分词和倒排列表能快速定位包含关键词的文档,且支持相关性评分和多种搜索模式(自然语言模式、布尔模式)。
  5. 索引是不是越多越好?

    • 绝对不是。索引的代价:
      • 空间代价:每个索引都是一棵 B+Tree,占用磁盘和内存。
      • 时间代价:DML(增删改)操作需要维护所有索引树,降低写入性能。
      • 优化器代价:索引过多会增加优化器选择执行计划的时间。
    • 建议:通常单表索引数不建议超过 5 个,核心是覆盖高频且性能关键查询。

【直击痛点:关键数字与设计】

  • 为什么 B+Tree 通常 3-4 层就能存亿级数据? 假设一个页(Page)大小为 16KB,一个主键(如 BIGINT)为 8 字节,一个指针为 6 字节。那么一个非叶子节点页大约可存储:16KB / (8B+6B) ≈ 1170 个键值对。假设叶子节点一行数据 1KB,则一页可存约 16 行。

    • 计算:
      • 第一层(根):1 页, 1170 个指针。
      • 第二层:1170 页,每页 1170 个指针 → 共 1170 * 1170 ≈ 1.37M 个指针。
      • 第三层(叶子):1.37M 页,每页 16 行 → 总行数约 1.37M * 16 ≈ 2190 万。
      • 若为四层:1170^3 * 16 ≈ 256 亿。因此,三层足以支撑千万级,四层支撑百亿级。
  • 联合索引字段顺序如何设计?

    1. 区分度最高的列放左边(选择性高),能最快过滤数据。
    2. 考虑查询频率和查询类型,常作为查询条件的列优先。
    3. 考虑覆盖索引,将查询中需要返回的列加到索引末尾。
    4. 遵循最左前缀原则,避免设计出无法被使用的索引。

【逻辑复现:一次索引查询的旅程(以 InnoDB 为例)】

场景:SELECT * FROM users WHERE name = ‘Alice’;, name 字段上有普通二级索引。

Step 1: 索引查找 存储引擎从 name 索引的 B+Tree 根节点开始,利用二分查找逐层向下,直到在叶子节点找到 ‘Alice’ 对应的主键 ID(如 id=5)。

Step 2: 回表 引擎拿着这个主键 ID(id=5),回到**聚簇索引(主键索引)**的 B+Tree 中,同样从根开始查找,直到定位到存储了完整 users 表中 id=5 这一行数据的叶子页。

Step 3: 数据返回 引擎从该页中读取整行数据,返回给 Server 层。

Step 4: 若使用覆盖索引 如果查询是 SELECT id FROM users WHERE name = ‘Alice’;,由于 id 已经在 name 索引的叶子节点中(二级索引存主键值),引擎在 Step 1 后即可直接返回结果,跳过 Step 2 和 Step 3,性能大幅提升。

【版本差异】

  • MySQL 5.6:引入了索引下推(ICP),显著优化了联合索引中范围查询后的字段过滤。
  • MySQL 5.7:支持生成列(Generated Columns) 及其索引,可用于对 JSON 数据类型建立索引。
  • MySQL 8.0:
    • 支持降序索引(DESC 在索引定义中生效),优化 ORDER BY a DESC, b DESC 查询。
    • 支持函数索引(如 CREATE INDEX idx ON t1 ((JSON_EXTRACT(col, ‘$.path’))))。
    • 废弃了查询缓存(Query Cache),更强调索引和引擎层优化。

总结:选择正确的索引类型是数据库性能优化的基石。理解其底层数据结构(尤其是 B+Tree)、存储方式(聚簇/非聚簇)以及 MySQL 的版本特性,才能设计出高效的索引策略,在空间和时间成本间取得最佳平衡。

My avatar

文章看完了,不打算去别的篇章转转吗?👀 感谢你的耐心阅读!如果你有问题想探讨,或者发现了文中的 Bug,请务必通过页脚的链接联系我


More Posts

# MySQL 的索引下推是什么?

7 min read

索引下推(Index Condition Pushdown,ICP)是 MySQL 5.6 引入的一项查询优化技术,其本质是将 WHERE 子句中部分过滤条件下推到存储引擎层执行,减少回表次数和服务器层的数据处理量。

Read

Comments