一、什么是回表?
不了解什么是聚簇索引和非聚簇索引的小伙伴可以先看下《什么是聚簇索引和非聚簇索引?》
什么是回表呢?当我们要查询数据的时候,如果是通过主键ID查询,那么直接会在聚簇索引查询,而如果是通过其他索引查询,就会先通过非聚簇索引查询拿到对应的主键ID,那么使用主键ID通过聚簇索引再一次查询才能拿到我们查询的数据。这个过程叫做回表
二、怎么减少回表的次数?
由于回表次数过多会影响性能,所以我们尽量要减少回表的次数
1、覆盖索引
覆盖索引指的执行查询语句时只需要在非聚簇索引中查询即可,不需要进行回表查询,主要的做法是通过设置联合索引覆盖需要查询的结果字段
比如要查询用户名称和年龄,sql是select * from user where age = 18;
- 由于只需要查询用户名称和年龄,所以sql可以优化为
select name,age from user where age = 18
- 由于要同时查询用户名称和年龄,所以要建立一个联合索引作为非聚簇索引
key idx_age_name(age,name)
这样子我们就完成了覆盖索引,查询数据时只需要在非聚簇索引中拿到查询结果字段即可,无需回表查询
2、索引下推(系统优化)
索引下推是MySQL5.6引入的一种优化技术,默认开启,可以使用set optimizer_switch = 'index_condition_pushdown=off'
将其关闭
索引下推主要的目的是减少数据查询中不必要的数据读取和计算,实现原理是将原本由Server层做的索引条件检查下推给索引层面来做,从而减少回表次数
比如要查询名为Lisi、所在城市名包含Z、且年龄大于25的用户,sql是select * from user where name = ‘Lisi’ and city like ‘%Z%’ and age > 25;同时创建联合索引(name,city)
-- 数据
mysql> select * from user;
+----+----------+-----------+------+
| id | name | city | age |
+----+----------+-----------+------+
| 1 | ZhaoDa | BeiJing | 20 |
| 2 | QianEr | ShangHai | 21 |
| 3 | SunSan | GuanZhou | 22 |
| 4 | LiSi | ShenZhen | 24 |
| 5 | ZhouWu | NingBo | 25 |
| 6 | WuLiu | HangZhou | 26 |
| 7 | ZhengQi | NanNing | 27 |
| 8 | WangBa | YinChuan | 28 |
| 9 | LiSi | TianJin | 29 |
| 10 | ZhangSan | NanJing | 30 |
| 11 | CuiShi | ZhengZhou | 65 |
| 12 | LiSi | KunMing | 29 |
| 13 | LiSi | ZhengZhou | 30 |
+----+----------+-----------+------+
13 rows in set (0.00 sec)
未使用索引下推:
- 通过联合索引(name,city),通过非聚簇索引找到name为Lisi的4条记录(由于city用的是模糊查询,不走索引),并拿到主键ID
- 根据步骤1拿到的主键ID,去聚簇索引找到对应的数据,返回给Server层(回表4次)
- Server层通过where条件
name="LiSi" and city like "%Z%" and age > 25
过滤,最终剩下1条记录
使用索引下推:
- 通过联合索引(name,city),通过非聚簇索引找到name为Lisi的4条记录(由于city用的是模糊查询,不走索引),并拿到主键ID
- 使用索引下推,结合联合索引(name,city),索引直接过滤`city like ‘%Z%’,剩下2条记录
- 根据步骤2拿到的主键ID,去聚簇索引找到对应的数据,返回给Server层(回表1次)
- Server层通过剩下的where条件
age>25
过滤,最终剩下1条记录
最后,我们通过explain语句可以看到确实是使用了索引下推(Extra显示Using index condition)
mysql> explain select * from user where name = "LiSi" and city like "%Z%" and age > 25;
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+------------------------------------+
| 1 | SIMPLE | user | NULL | ref | idx_name_city | idx_name_city | 99 | const | 4 | 7.69 | Using index condition; Using where |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+------------------------------------+
1 row in set, 1 warning (0.00 sec)