MySQL索引分类详解:从四个维度全面理解索引

一、引言

MySQL索引是提高数据库查询性能的关键技术,为了更好地理解和使用索引,我们需要从多个维度来认识它。本文将从数据结构、物理存储、字段特性和字段个数这四个角度,全面介绍MySQL索引的分类。

二、按「数据结构」分类

2.1 B+tree索引

特点:

  • 最常用的索引类型
  • 树形数据结构,多路平衡查找树
  • 叶子节点相互链接,适合范围查询
  • 非叶子节点只存储索引值

适用场景:

  • 等值查询(=)
  • 范围查询(>, <, BETWEEN)
  • 排序操作(ORDER BY)
  • 分组操作(GROUP BY)

2.2 Hash索引

特点:

  • 基于哈希表实现
  • 只能精确匹配所有列
  • 查询复杂度O(1)
  • 无法进行范围查询

适用场景:

  • 等值查询
  • 查询结果高度确定
  • 数据量较大但查询频繁

2.3 Full-text索引

特点:

  • 全文索引,用于文本搜索
  • 支持分词和相关性评分
  • 占用空间较大

适用场景:

  • 文章内容检索
  • 关键词搜索
  • 相似度匹配

三、按「物理存储」分类

3.1 聚簇索引(主键索引)

特点:

  • 数据行实际存储在索引的叶子页中
  • 一个表只能有一个聚簇索引
  • 通常是主键索引
  • 叶子节点包含所有列数据

示例:

CREATE TABLE users (
    id INT PRIMARY KEY,  -- 聚簇索引
    name VARCHAR(50),
    age INT
);

3.2 二级索引(辅助索引)

特点:

  • 叶子节点存储主键值
  • 需要回表查询完整数据
  • 一个表可以有多个二级索引

示例:

CREATE INDEX idx_name ON users(name);  -- 二级索引

四、按「字段特性」分类

4.1 主键索引

特点:

  • 唯一标识数据行
  • 不允许NULL值
  • 自动创建聚簇索引

示例:

CREATE TABLE products (
    product_id INT PRIMARY KEY,  -- 主键索引
    name VARCHAR(100)
);

4.2 唯一索引

特点:

  • 列值必须唯一
  • 允许NULL值
  • 可以有多个唯一索引

示例:

CREATE UNIQUE INDEX idx_email ON users(email);  -- 唯一索引

4.3 普通索引

特点:

  • 最基本的索引类型
  • 无特殊限制
  • 允许重复值和NULL值

示例:

CREATE INDEX idx_age ON users(age);  -- 普通索引

4.4 前缀索引

特点:

  • 针对长字符串列的部分建立索引
  • 减少索引空间占用
  • 可能降低索引选择性

示例:

CREATE INDEX idx_name_prefix ON users(name(10));  -- 前缀索引,使用前10个字符

五、按「字段个数」分类

5.1 单列索引

特点:

  • 只包含一个字段
  • 适用于单字段查询

示例:

CREATE INDEX idx_single ON users(age);  -- 单列索引

5.2 联合索引(复合索引)

特点:

  • 包含多个字段
  • 遵循最左前缀原则
  • 可以覆盖多个查询场景

示例:

CREATE INDEX idx_compound ON users(name, age, city);  -- 联合索引

最左前缀原则说明:

  • 可以使用(name)
  • 可以使用(name, age)
  • 可以使用(name, age, city)
  • 不能跳过中间字段使用

因此,使用联合索引时,存在最左匹配原则,也就是按照最左优先的方式进行索引的匹配。在使用联合索引进行查询的时候,如果不遵循「最左匹配原则」,联合索引会失效,这样就无法利用到索引快速查询的特性了。

比如,如果创建了一个 (a, b, c) 联合索引,如果查询条件是以下这几种,就可以匹配上联合索引:

where a=1where a=1 and b=2 and c=3where a=1 and b=2

需要注意的是,因为有查询优化器,所以 a 字段在 where 子句的顺序并不重要。(也就是说where a=1 and b=2;和where b=2 and a=1;是一样的,a 和 b 字段都能利用联合索引)

但是,如果查询条件是以下这几种,因为不符合最左匹配原则,所以就无法匹配上联合索引,联合索引就会失效:

where b=2where c=3where b=2 and c=3

上面这些查询条件之所以会失效,是因为(a, b, c) 联合索引,是先按 a 排序,在 a 相同的情况再按 b 排序,在 b 相同的情况再按 c 排序。所以,b 和 c 是全局无序,局部相对有序的,这样在没有遵循最左匹配原则的情况下,是无法利用到索引的。

联合索引有一些特殊情况,并不是查询过程使用了联合索引查询,就代表联合索引中的所有字段都用到了联合索引进行索引查询,也就是可能存在部分字段用到联合索引的 B+Tree,部分字段没有用到联合索引的 B+Tree 的情况。

这种特殊情况就发生在范围查询。联合索引的最左匹配原则会一直向右匹配直到遇到「范围查询」就会停止匹配。也就是范围查询的字段可以用到联合索引,但是在范围查询字段的后面的字段无法用到联合索引。

六、相关问题

1.联合索引 (a, b,c),where条件是 a=2 and c = 1,能用到联合索引吗?

会用到联合索引,但是只有 a 才能走索引,c 无法走索引,因为不符合最左匹配原则。虽然 c 无法走索引, 但是 c 字段 在 5.6 版本之后,会有索引下推的优化,能减少回表查询的次数。

2.联合索引ABC,现在有个执行语句是A = XXX and C < XXX,索引怎么走

根据最左匹配原则,A可以走联合索引,C不会走联合索引,但是C可以走索引下推

3.联合索引(a,b,c) ,查询条件 where b > xxx and a = x 会生效吗

索引会生效,a 和 b 字段都能利用联合索引,符合联合索引最左匹配原则。

七、索引选择建议

7.1 常见场景的索引选择

  1. 查询单个记录

    • 使用主键索引或唯一索引
    • 适合B+tree索引
  2. 范围查询

    • 使用B+tree索引
    • 避免使用Hash索引
  3. 全文检索

    • 使用Full-text索引
    • 适合文本搜索场景
  4. 多字段查询

    • 考虑创建联合索引
    • 注意最左前缀原则

7.2 索引设计原则

  1. 适度建立索引

    • 不是越多越好
    • 考虑维护成本
  2. 针对查询优化

    • 根据实际查询需求
    • 避免无用索引
  3. 考虑空间开销

    • 合理使用前缀索引
    • 避免过多的联合索引

八、总结

通过从数据结构、物理存储、字段特性和字段个数这四个维度来理解MySQL索引,我们可以:

  1. 更好地理解索引的工作原理
  2. 根据实际需求选择合适的索引类型
  3. 优化查询性能
  4. 合理设计数据库结构

在实际应用中,需要根据具体的业务场景和查询需求,综合考虑这些分类特点,选择最适合的索引方案。