好的,我们系统地梳理一下 MySQL 的索引,包括类型、作用、底层原理和使用场景。这样你对回表、辅助索引、聚簇索引等概念会更清楚。


1️⃣ 什么是索引

**索引 (Index)**是数据库为了加速查询而对一列或多列数据建立的数据结构,相当于书的目录,可以快速定位数据,而无需全表扫描。

作用:

  • 提高查询速度 (WHERE、JOIN、ORDER BY、GROUP BY)
  • 降低 I/O 消耗
  • 支持排序和范围查询

代价:

  • 占用额外存储空间
  • 插入/更新/删除时需要维护索引,可能降低写入性能

2️⃣ MySQL 的主要索引类型

(1) 主键索引 (Primary Key / 聚簇索引)

  • 特性
    • 唯一标识行
    • 数据行和索引在同一个 B+Tree(聚簇索引)
  • 示例
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT
);
  • 查询 id 时直接访问数据,不回表

(2) 唯一索引 (Unique Index)

  • 特性
    • 保证列值唯一,可以有 NULL(多次,视数据库而定)
  • 示例
CREATE UNIQUE INDEX idx_email ON users(email);

(3) 普通索引 (普通非唯一索引 / Secondary Index)

  • 特性
    • 加速查询,不保证唯一
    • InnoDB 存储为 辅助索引,只存索引列 + 主键
  • 示例
CREATE INDEX idx_age ON users(age);
  • 查询 age=18 时:
    1. 用 idx_age 找到主键 id → 回表拿其他列

(4) 复合索引 (Composite / Multi-column Index)

  • 特性
    • 索引多个列,遵循 左前缀原则
    • (col1, col2),可以高效查询 col1(col1, col2),但单独查询 col2 效率不高
  • 示例
CREATE INDEX idx_name_age ON users(name, age);

(5) 全文索引 (Full-text Index)

  • 特性
    • 用于文本搜索 (MATCH...AGAINST)
    • 只能在 CHAR / VARCHAR / TEXT 类型
  • 示例
CREATE FULLTEXT INDEX idx_content ON articles(content);

(6) 空间索引 (Spatial Index)

  • 特性
    • 用于几何类型 (如 POINT, POLYGON)
    • 支持空间查询 (距离、交集等)
  • 示例
CREATE SPATIAL INDEX idx_location ON places(location);

3️⃣ MySQL 索引底层结构

  • B+Tree 索引(最常用)
    • 聚簇索引 (主键索引) 存储数据行
    • 辅助索引 (普通索引) 存储索引列 + 主键
  • 哈希索引
    • Memory 存储引擎使用
    • 只支持精确匹配,不支持范围查询
  • 全文索引 / R-Tree / GiST / SPATIAL
    • 针对特殊类型数据

4️⃣ 索引的选择原则

  1. 高选择性列建索引(列值重复少)
  2. WHERE、JOIN、ORDER BY、GROUP BY 用到的列建索引
  3. 频繁更新/插入的表慎用过多索引
  4. 考虑覆盖索引(查询列包含在索引中,避免回表)

5️⃣ 小结

索引类型 特点 作用
主键索引 PK 聚簇索引,唯一,不可为 NULL 唯一标识,快速查询
唯一索引 Unique 唯一,可为 NULL 保证数据唯一
普通索引 Index 不唯一,辅助索引 加速查询
复合索引 Composite 多列组合索引,左前缀有效 多列查询加速
全文索引 Fulltext 用于文本搜索 MATCH ... AGAINST
空间索引 Spatial 用于几何类型数据 空间查询

 

画一个 MySQL InnoDB 索引与回表示意图,把主键索引 (聚簇索引)、辅助索引 (普通索引)、回表流程都画清楚。


假设表结构:

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT,
    INDEX idx_age(age)
);
  • **聚簇索引 (主键索引)**存储完整数据行
  • **辅助索引 (idx_age)**只存索引列 age + 主键 id

索引示意图

┌───────────────────────────────┐
│       users 主表 (聚簇索引)│
│ id | name  | age               │
│-------------------------------│
│ 1  | Tom   | 18               │
│ 2  | Lily  | 20               │
│ 3  | Jack  | 18               │
└───────────────────────────────┘

┌───────────────┐
│ idx_age 索引页 │  (辅助索引)
│ age | id      │
│----------------│
│ 18  | 1       │
│ 18  | 3       │
│ 20  | 2       │
└───────────────┘

查询流程示意

1️⃣ 查询 id 列,不回表

SELECT id FROM users WHERE age = 18;

流程:

idx_age 索引页查 age=18 -> 得到 id=[1,3]
直接返回 id=[1,3],不回表

2️⃣ 查询 name 列,需要回表

SELECT name FROM users WHERE age = 18;

流程:

1. idx_age 索引页查 age=18 -> 得到 id=[1,3]
2. 回表到 users 主表,根据 id 查 name
   id=1 -> Tom
   id=3 -> Jack
3. 返回结果 [Tom, Jack]

直观理解

查询条件列在辅助索引 -> 找到主键 -> 再回主表查其他列
┌─────────┐
│ idx_age  │
│ age=18   │
│ id -> 1  │
│ id -> 3  │
└────┬────┘
     │ 回表
     ▼
┌───────────────┐
│ users 主表    │
│ id | name | age│
│ 1  | Tom  | 18│
│ 3  | Jack | 18│
└───────────────┘
返回 name

总结

  • 聚簇索引 (主键索引):存储完整行,查询列在主键里不回表
  • 辅助索引:只存索引列 + 主键,查询其他列需要回表
  • 回表:从辅助索引跳到主表获取完整数据

如果你需要,我可以画一个 B+Tree 结构示意图,把 聚簇索引页、辅助索引页和回表过程 画得像数据库内部真实访问一样,这样你看 MySQL 索引原理就更直观了。

好,我给你画一个 B+Tree 结构示意图,展示 MySQL InnoDB 的 聚簇索引、辅助索引以及回表流程,让你更直观理解索引是如何查找数据的。


假设表结构

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT,
    INDEX idx_age(age)
);
  • 主键索引 (聚簇索引) 存储完整数据行
  • 辅助索引 (idx_age) 只存索引列 age + 主键 id

1️⃣ 聚簇索引 B+Tree(主表)

聚簇索引 B+Tree(主键 id)
         [2]
        /   \
      [1]   [3]

叶子节点存储完整行:
[1 | Tom | 18], [2 | Lily | 20], [3 | Jack | 18]
  • 查询主键 id=3 → 直接找到叶子节点,不用回表

2️⃣ 辅助索引 B+Tree(idx_age)

辅助索引 B+Tree(age -> id)
         [18, 20]
        /       \
      [18]     [20]

叶子节点存储:
[18 | 1], [18 | 3], [20 | 2]
  • 查询 age=18 → 找到 id=1 和 id=3
  • 因为查询列是 name,不在辅助索引里 → 回表到聚簇索引查完整数据

3️⃣ 回表流程示意

查询:SELECT name FROM users WHERE age=18;

1️⃣ 辅助索引查 age=18 -> 得到 id=[1,3]
          idx_age
         ┌─────┐
         │18->1│
         │18->3│
         └─────┘
               │
2️⃣ 回表查主键索引 (聚簇索引)
       users 主表 (聚簇索引)
       ┌───────────────┐
       │ 1 | Tom  | 18 │
       │ 3 | Jack | 18 │
       └───────────────┘
               │
3️⃣ 返回查询结果
       [Tom, Jack]

4️⃣ 总结

  • 聚簇索引:存数据,查询主键直接命中叶子节点
  • 辅助索引:只存索引列+主键,查询其他列必须回主表 (回表)
  • 回表:辅助索引 → 主键 → 数据行,增加 I/O

 

 

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。