索引类型:聚簇索引与非聚簇索引、唯一索引、联合索引、全文索引
索引这东西,说白了就是数据库的「目录」。没有它,查询就是全表扫描——数据量小还好,上了百万级你就等着报警吧。我这些年调过的慢查询,十有八九都是索引没用好。
但索引也不是随便建的。建错了,写操作变慢,磁盘空间暴涨。建对了,查询速度能提升几个数量级。今天咱们就把几种核心索引类型掰开揉碎讲清楚。
核心观点:索引类型的选择,取决于你的查询模式。没有银弹,只有匹配。
聚簇索引 vs 非聚簇索引
这是最基础、也最容易混淆的一对概念。我面试时经常问,能讲清楚的人不多。
聚簇索引,表数据的物理存储顺序和索引顺序一致。一张表只能有一个聚簇索引。InnoDB 里,主键就是聚簇索引。如果你没定义主键,它会选一个唯一非空索引;还没有,就隐式生成一个 6 字节的 rowid。
聚簇索引的叶子节点存的是整行数据。所以通过主键查数据,一次 B+ 树搜索就能拿到全部字段,不需要回表。这就是为什么主键查询那么快。
非聚簇索引,叶子节点存的是主键值(InnoDB)或行指针(MyISAM)。查询时先找到主键,再回聚簇索引取数据——这个过程叫「回表」。回表一次还好,回表几百次性能就崩了。
| 对比维度 | 聚簇索引 | 非聚簇索引 |
|---|---|---|
| 每表数量 | 1 个 | 多个 |
| 叶子节点内容 | 整行数据 | 主键值(InnoDB) |
| 是否需要回表 | 否 | 是 |
| 物理顺序 | 与索引顺序一致 | 与索引顺序无关 |
| 适用场景 | 主键查询、范围查询 | 非主键列的精确匹配 |
我的经验:建表时一定要选对聚簇索引的列。我见过有人用 UUID 做主键,结果插入时频繁页分裂,写入性能惨不忍睹。自增整数做主键,在大多数场景下是最稳的选择。
唯一索引
唯一索引保证索引列的值全局唯一。它和主键的区别在于:唯一索引允许 NULL 值(而且可以多个 NULL),主键不允许。
唯一索引有两个作用:一是约束数据完整性,二是加速查询。MySQL 对唯一索引的查询优化优先级很高,因为它知道最多只返回一条记录。
-- 创建唯一索引
CREATE UNIQUE INDEX idx_user_email ON users(email);
-- 或者建表时指定
CREATE TABLE users (
id INT PRIMARY KEY,
email VARCHAR(255) UNIQUE,
name VARCHAR(100)
);
我曾经踩过的坑:在业务代码里先查再插来「模拟」唯一约束,高并发下总有重复数据漏进去。后来改成唯一索引 + INSERT IGNORE,问题彻底解决。数据库能做的事,别让应用层做。
联合索引
联合索引,也叫复合索引,是多个列组合成一个索引。它遵循「最左前缀原则」——查询条件必须从索引的最左列开始匹配,才能用到索引。
举个例子,索引 (a, b, c) 能匹配的查询模式:
WHERE a = 1✅ 用到索引WHERE a = 1 AND b = 2✅ 用到索引WHERE a = 1 AND b = 2 AND c = 3✅ 用到索引WHERE b = 2❌ 用不到索引WHERE a = 1 AND c = 3⚠️ 只用到了 a 列
为什么会这样?因为 B+ 树是按索引列的顺序构建的。先按 a 排序,a 相同再按 b 排序,b 相同再按 c 排序。跳过前面的列直接查后面的,树就不知道怎么走了。
我建议:设计联合索引时,把区分度高的列放前面。比如 (status, created_at) 和 (created_at, status),前者通常更优——因为 status 枚举值少,created_at 区分度高。你想想看,先过滤掉 90% 的数据,再处理剩下的 10%,效率肯定更高。
全文索引
全文索引专门用来处理文本搜索。LIKE '%keyword%' 这种写法,数据量一大就废了——它不走索引,全表扫描。全文索引用倒排索引(Inverted Index)实现,把文档拆成词条,再映射到文档 ID。
MySQL 的全文索引只支持 MyISAM 和 InnoDB(5.6 以后)。用法很简单:
-- 创建全文索引
CREATE FULLTEXT INDEX idx_content ON articles(content);
-- 查询
SELECT * FROM articles
WHERE MATCH(content) AGAINST('数据库优化' IN NATURAL LANGUAGE MODE);
全文索引有三种搜索模式:
- 自然语言模式:默认模式,按相关性排序
- 布尔模式:支持 +、-、* 等操作符,精确控制搜索逻辑
- 查询扩展模式:先搜一次,再用结果中的高频词扩展搜索
注意:全文索引有最小词长度限制(InnoDB 默认 3 个字符)。搜「Go」或「C++」这种短词,默认是搜不到的。需要修改 innodb_ft_min__size 参数。我之前做技术博客搜索时就栽过这个坑。
一张图看懂索引体系
下面这张图把几种索引的关系和适用场景串起来了。我建议你保存下来,面试前看一眼就够了。
如何选择索引类型
选索引类型,其实就是在问自己三个问题:
- 查询频率最高的列是什么?——优先建索引
- 查询是精确匹配还是范围查询?——精确匹配用唯一索引或普通索引,范围查询用聚簇索引或联合索引
- 是否需要文本搜索?——是的话上全文索引,别用 LIKE
我个人习惯:先跑一遍慢查询日志,找到 TOP 5 的慢 SQL。针对每个慢 SQL 的 WHERE 条件、JOIN 列、ORDER BY 列来设计索引。不要凭感觉建索引,要拿数据说话。