MySQL覆盖索引是什么,为什么能提升查询性能

前言

做SQL优化的同学肯定听说过覆盖索引,很多文章里都说用覆盖索引能提升查询性能。但是很多新手同学搞不懂覆盖索引到底是什么,为什么能提升性能。

这篇文章就把覆盖索引的知识点从头到尾讲清楚:什么是覆盖索引?为什么能提升性能?怎么判断是不是用了覆盖索引?怎么利用覆盖索引优化查询?看完之后你就彻底搞懂了。

一、什么是覆盖索引

先说说回表是什么。

MySQL的InnoDB引擎,主键索引是聚簇索引,叶子节点直接存整行数据。普通索引的叶子节点存的是主键值。

如果你用普通索引查询,查到主键值之后,还要再去主键索引里查一遍,拿到完整的行数据。这个过程就叫回表。

那什么是覆盖索引呢?就是:你要查询的字段,在索引里就都有了,不用再回表去主键索引里查了。这就叫覆盖索引,或者叫索引覆盖。

简单来说:查询需要的所有数据,索引里都有,不用回表,就是覆盖索引。

二、为什么覆盖索引能提升性能

为什么覆盖索引能提升性能?因为少了回表这一步。

我们对比一下:

没有覆盖索引的情况

  1. 先在普通索引里查,找到主键值
  2. 再拿着主键值去主键索引里查,拿到完整的行数据

这样要查两棵B+树,查了两次,当然慢。

有覆盖索引的情况

  1. 直接在索引里查到所有需要的数据,就完事了

这样只查了一棵B+树,少了回表这一步,当然快。

尤其是表很大的时候,回表要做随机IO,性能很差。如果不用回表,直接在索引里就能拿到数据,那性能提升就非常明显了。

三、怎么判断是不是覆盖索引

用explain看执行计划的时候,如果Extra列里显示 Using index,就说明用了覆盖索引,不用回表。

比如:

+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | users | ref   | name          | name | 767     | const|  10  | Using index |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+

看到Extra里的Using index了吗?这就说明用了覆盖索引。

四、怎么利用覆盖索引优化查询

知道了覆盖索引的好处,那怎么利用它来优化查询呢?

1. 查询的时候只查需要的字段,不要SELECT *

很多同学写SQL的时候喜欢写SELECT *,把所有字段都查出来。这样你要查的字段太多了,索引里不可能全都有,就必须回表。

如果你只查需要的几个字段,那就有可能把这几个字段都加到索引里,这样就能用到覆盖索引了。

比如:

-- 不好的写法
SELECT * FROM users WHERE name = '张三';

-- 好的写法
SELECT id, name, age FROM users WHERE name = '张三';

2. 建联合索引,把经常查询的字段都加进去

如果你经常根据name查询,并且经常查name和age,那就建一个(name, age)的联合索引。

这样当你查SELECT name, age FROM users WHERE name = '张三'的时候,索引里就有name和age了,不用回表,直接就能拿到数据。

3. 把常用的查询字段加到索引里

除了WHERE条件的字段,SELECT里的字段也可以加到索引里,这样就能实现覆盖索引。

比如你经常查SELECT id, name, age FROM users WHERE name = ?,那就建一个(name, age)的联合索引,因为id是主键,InnoDB的普通索引叶子节点本来就存主键值,所以索引里就有id、name、age三个字段了,正好覆盖你的查询。

五、覆盖索引的注意点

1. 不是所有查询都能用覆盖索引

只有你要查询的字段都在索引里的时候,才能用覆盖索引。如果有字段不在索引里,那就必须回表。

2. 覆盖索引也不是万能的

不要为了覆盖索引,把所有字段都加到索引里。索引太多了,会影响插入和更新的性能。要权衡一下,哪些查询是高频的,值得为它建覆盖索引。

3. 主键索引天然就是覆盖索引

如果你是用主键查询,那本来就是在主键索引里查,直接就能拿到所有数据,天然就是覆盖索引。

常见坑

坑1:以为只要用了索引就是覆盖索引

很多同学以为只要查询用到了索引,就是覆盖索引。其实不是,用到索引只是说用索引找到了主键值,如果你还要查其他字段,还是要回表。只有Extra里显示Using index,才是真的覆盖索引。

坑2:写SELECT *,用不了覆盖索引

很多同学写SQL的时候喜欢SELECT *,结果要查的字段太多了,索引里根本放不下,就用不了覆盖索引。记住:只查需要的字段,别查所有字段。

坑3:为了覆盖索引,索引建得太多

很多同学为了让某个查询用上覆盖索引,把那个查询的所有字段都加到索引里。结果一个表建了好几十个索引,插入更新的时候要维护这么多索引,性能很差。覆盖索引是好,但是不要滥用,要权衡。

坑4:不知道Using index就是覆盖索引

很多同学看explain的时候,看到Extra里的Using index不知道是什么意思。记住:Using index就是覆盖索引,不用回表,性能很好。

坑5:联合索引的顺序不对

很多同学建联合索引的时候,顺序建反了,结果用不了覆盖索引。记住:联合索引要满足最左前缀原则,WHERE条件里的字段要放在前面,SELECT的字段放在后面。

总结

MySQL覆盖索引的核心知识点:

  1. 什么是覆盖索引:查询需要的所有数据,索引里都有,不用回表
  2. 为什么能提升性能:少了回表这一步,不用查两棵B+树,减少IO
  3. 怎么判断:explain的Extra列里显示Using index,就是覆盖索引
  4. 怎么利用:
    • 不要写SELECT *,只查需要的字段
    • 建联合索引,把WHERE和SELECT的字段都加进去
  5. 注意点:不要为了覆盖索引建太多索引,要权衡性能

记住:覆盖索引是SQL优化里很重要的一个手段,很多时候只要把SELECT *改成只查需要的字段,再建个合适的联合索引,性能就能提升好几倍。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-5 09:07