首页 / MySQL 入门教程 / 索引基础与索引类型

MySQL 入门教程

索引基础与索引类型

本教程共 46 篇 · 第 40 篇 · 更新于 2026-07-30 · 约 13 分钟阅读

MySQLMySQL 入门教程索引B+树聚簇索引二级索引回表FULLTEXT

40. 索引基础与索引类型

本节目标:理解索引的本质和 B+ 树结构,搞清楚聚簇索引和二级索引的区别与回表机制,掌握各类索引的创建方式和适用场景。

40.1 索引是什么

索引(Index) 是一种数据结构,用来加速查询。就像书的目录:要找某个知识点,不用一页页翻,先查目录找到页码,直接翻过去。

没有索引时,MySQL 要从头到尾扫描整张表(全表扫描,Full Table Scan)来找数据。表越大越慢。有了索引,MySQL 可以在索引结构上快速定位,几步就能找到数据。

-- 创建索引
CREATE INDEX idx_email ON users(email);

-- 查询时自动使用索引(MySQL 优化器自动判断)
SELECT * FROM users WHERE email = 'zhangsan@test.com';
Note

索引提升查询速度,但也有代价:占用额外存储空间,写入时需要同步维护索引(INSERT/UPDATE/DELETE 变慢)。索引不是越多越好。

40.2 B+ 树:索引的底层数据结构

InnoDB 的索引使用 B+ 树(B+ Tree) 数据结构。理解 B+ 树是理解索引性能的关键。

B+ 树长什么样

B+ 树是一棵多叉平衡树,特点是:

  • 非叶子节点只存索引键和子节点指针,不存数据;
  • 叶子节点存所有数据,且按顺序排列;
  • 叶子节点之间用双向链表连接。
            [30 | 60]              <- 非叶子节点(只存键值)
           /    |    \
     [10|20] [40|50] [70|80]      <- 叶子节点(存数据)
       <->    <->     <->

为什么用 B+ 树

查询方式无索引(全表扫描)B+ 树索引
100 万行找 1 行扫描 100 万行树高约 3 层,3 次磁盘 IO
范围查询(如 id > 50)扫描 100 万行定位到 50,沿链表往后走

B+ 树的关键优势:

  1. 矮胖:每个节点能存很多键值,树很矮(3-4 层就能存上千万行),磁盘 IO 次数少;
  2. 范围查询快:叶子节点是有序链表,找到起点后顺着链表走就行;
  3. 数据稳定:数据都在叶子节点,查询性能稳定。
Tip

InnoDB 默认每个页(Page)16KB。一个 B+ 树节点就是一个页。非叶子节点只存键值(假设 BIGINT 8 字节 + 指针 6 字节 = 14 字节),一个页能放约 1170 个键值。三层 B+ 树:1170 x 1170 x 16 ≈ 2100 万行,只需要 3 次磁盘 IO 就能找到任意一行。

40.3 聚簇索引 vs 二级索引

InnoDB 的索引分为两大类,这是理解索引体系的核心。

聚簇索引(Clustered Index)

聚簇索引把数据和索引存在一起,B+ 树的叶子节点直接存放完整的行数据。一张表只能有一个聚簇索引。

InnoDB 的聚簇索引就是主键索引。如果你没显式定义主键,InnoDB 会选第一个 NOT NULL 的唯一索引;如果也没有,InnoDB 会自动生成一个隐藏的 6 字节行 ID 作为聚簇索引。

聚簇索引 B+ 树:
[非叶子节点: 主键值 + 指针]
  ...
[叶子节点: 主键值 + 完整行数据]

二级索引(Secondary Index)

二级索引也叫非聚簇索引或辅助索引。它的 B+ 树叶子节点不存完整行数据,而是存索引列的值 + 对应的主键值

二级索引 B+ 树(以 email 索引为例):
[非叶子节点: email 值 + 指针]
  ...
[叶子节点: email 值 + 主键 id]

回表(Table Lookup)

通过二级索引查到主键值后,还需要去聚簇索引里查完整行数据,这个过程叫回表

-- 假设 email 上有二级索引
SELECT * FROM users WHERE email = 'zhangsan@test.com';

执行过程:

  1. 在 email 二级索引 B+ 树中查找 zhangsan@test.com,找到对应主键 id = 1
  2. id = 1 去聚簇索引 B+ 树中查找,拿到完整行数据。

两次 B+ 树查找,这就是回表的代价。

Warning

回表意味着额外的磁盘 IO。如果查询只需要索引列的值,就不需要回表,这就是”覆盖索引”的概念,下一节会详细讲。

聚簇索引 vs 二级索引对比

特性聚簇索引二级索引
叶子节点存什么完整行数据索引列值 + 主键值
每张表数量1 个多个
查询是否需要回表不需要通常需要
建索引方式自动(主键)手动 CREATE INDEX

40.4 各类索引

主键索引

就是聚簇索引本身,上一节主键约束已讲过。建表时定义主键即自动创建。

唯一索引(UNIQUE Index)

索引列值不能重复,和 UNIQUE 约束本质相同:

-- 方式一:建表时定义
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(100) UNIQUE,  -- 自动建唯一索引
    ...
);

-- 方式二:单独创建
CREATE UNIQUE INDEX idx_email ON users(email);

唯一索引既能保证数据唯一,又能加速查询,是最常用的索引类型之一。

普通索引(Normal Index)

最基本的索引,没有任何约束:

-- 创建
CREATE INDEX idx_age ON users(age);

-- 或建表时加
ALTER TABLE users ADD INDEX idx_age(age);

联合索引(Composite Index)

多列组合的索引:

CREATE INDEX idx_user_status ON orders(user_id, status);

联合索引按从左到右的顺序排列。最左前缀原则在下一节详讲。

前缀索引(Prefix Index)

对长字符串列,只索引前面一部分字符,节省空间:

-- 只索引 email 前 10 个字符
CREATE INDEX idx_email_prefix ON users(email(10));
-- 查看 email 列的值分布,选择合适的前缀长度
SELECT
    COUNT(*) AS total,
    COUNT(DISTINCT LEFT(email, 5)) AS prefix_5,
    COUNT(DISTINCT LEFT(email, 10)) AS prefix_10,
    COUNT(DISTINCT LEFT(email, 15)) AS prefix_15
FROM users;
-- 选择区分度接近完整列的前缀长度
Tip

前缀索引能节省空间,但不能用于 ORDER BY 和 GROUP BY(因为索引只存了部分值)。也不能做覆盖索引。

全文索引(FULLTEXT Index)

用于全文搜索,支持自然语言分词检索:

-- 创建全文索引
CREATE FULLTEXT INDEX ft_content ON articles(content);

-- 使用全文搜索
SELECT * FROM articles
WHERE MATCH(content) AGAINST('MySQL 索引');
-- 布尔模式:支持 +(必须包含)和 -(不包含)
SELECT * FROM articles
WHERE MATCH(content) AGAINST('+MySQL -Oracle' IN BOOLEAN MODE);
Note

全文索引适合文本搜索场景(如文章、商品描述)。中文需要使用 ngram 分词插件(MySQL 5.7.6+ 内置支持)。短字段(如用户名)用 LIKE 就行,不需要全文索引。

40.5 创建和删除索引

-- 方式一:CREATE INDEX
CREATE INDEX idx_age ON users(age);
CREATE UNIQUE INDEX idx_email ON users(email);
CREATE INDEX idx_multi ON orders(user_id, status);

-- 方式二:ALTER TABLE
ALTER TABLE users ADD INDEX idx_age(age);
ALTER TABLE users ADD UNIQUE INDEX idx_email(email);
ALTER TABLE users ADD FULLTEXT INDEX ft_content(content);

-- 删除索引
DROP INDEX idx_age ON users;
ALTER TABLE users DROP INDEX idx_email;

-- 查看表的索引
SHOW INDEX FROM users;
Note

SHOW INDEX FROM usersKey_name 列是索引名,Column_name 列是索引包含的列。主键索引的 Key_namePRIMARY

40.6 索引的代价

方面代价
空间每个索引是一棵 B+ 树,占额外存储
写入INSERT/UPDATE/DELETE 需要同步维护所有索引
优化器选择索引太多,优化器可能选错索引
Tip

一个经验法则:一张表的索引数量控制在 5-6 个以内。经常查询的列建索引,很少查询的列不建。联合索引能覆盖多个查询场景,比建多个单列索引更高效。

40.7 小结

  • 索引是加速查询的数据结构,InnoDB 用 B+ 树实现;
  • B+ 树矮胖有序,3-4 层就能存千万行数据,查询只需 3-4 次磁盘 IO;
  • 聚簇索引(主键)叶子节点存完整行数据,一张表只有一个;
  • 二级索引叶子节点存索引列值 + 主键值,查询完整行需要回表;
  • 常用索引类型:主键索引、唯一索引、普通索引、联合索引、前缀索引、全文索引;
  • 索引有空间和写入代价,不是越多越好,控制在 5-6 个以内。

下一节讲索引设计原则和最左前缀原则,学会怎么科学地建索引。