什么是回表,怎么减少回表的次数?


一、什么是回表?

不了解什么是聚簇索引和非聚簇索引的小伙伴可以先看下《什么是聚簇索引和非聚簇索引?》

什么是回表呢?当我们要查询数据的时候,如果是通过主键ID查询,那么直接会在聚簇索引查询,而如果是通过其他索引查询,就会先通过非聚簇索引查询拿到对应的主键ID,那么使用主键ID通过聚簇索引再一次查询才能拿到我们查询的数据。这个过程叫做回表

二、怎么减少回表的次数?

由于回表次数过多会影响性能,所以我们尽量要减少回表的次数

1、覆盖索引

覆盖索引指的执行查询语句时只需要在非聚簇索引中查询即可,不需要进行回表查询,主要的做法是通过设置联合索引覆盖需要查询的结果字段

比如要查询用户名称和年龄,sql是select * from user where age = 18;

  1. 由于只需要查询用户名称和年龄,所以sql可以优化为select name,age from user where age = 18
  2. 由于要同时查询用户名称和年龄,所以要建立一个联合索引作为非聚簇索引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)

未使用索引下推

  1. 通过联合索引(name,city),通过非聚簇索引找到name为Lisi的4条记录(由于city用的是模糊查询,不走索引),并拿到主键ID
  2. 根据步骤1拿到的主键ID,去聚簇索引找到对应的数据,返回给Server层(回表4次
  3. Server层通过where条件name="LiSi" and city like "%Z%" and age > 25过滤,最终剩下1条记录
    未使用索引下推

使用索引下推

  1. 通过联合索引(name,city),通过非聚簇索引找到name为Lisi的4条记录(由于city用的是模糊查询,不走索引),并拿到主键ID
  2. 使用索引下推,结合联合索引(name,city),索引直接过滤`city like ‘%Z%’,剩下2条记录
  3. 根据步骤2拿到的主键ID,去聚簇索引找到对应的数据,返回给Server层(回表1次
  4. 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)

文章作者: GaryLee
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 GaryLee !
  目录