一,MySQL中的回表是什么意思?
利用二级索引进行查询除索引列值和主键以外的值时,由于二级索引的叶子节点中存储的只有索引所对应列的值和主键id,这样就导致我们查询不到,所以Innodb就会重新使用查到的主键id回到表中找到对应的行数据,因为主键索引的叶子节点存储的是对应行的全部数据,所以可以找到
举个例子,这里使用select * from user where age = 20;来进行举例说明,user表上有三个字段,分别是id,name,age,这里age上有索引
(1)首先走age的二级索引,找到age = 20 的记录拿到主键值

(2)由于我们使用了select * 导致我们还需要name字段,但是age索引中并没有name,这时我们要用找到的主键id重新回到表中,找到全部对应行数据字段id,name,age

二,回表所带来的性能代价
回表并不是重新查询一遍表那么简单
因为查询二级索引所查询到的主键id并不是连续的,就比如age = 20 的用户有很多,所以查询到的id是无序的,可能的顺序:10,239,3,2134,21390,使用这些id去主键索引中查,会导致定位到不同的数据页,从而产生大量的随机IO
顺序IO:读写的数据在磁盘上是一个挨着一个的,读取一大块相邻磁盘页,磁头也会很快的进行移动,不会出现较大幅度的移动
随机IO:读写的数据分布在磁盘上的随机位置,如果数据一多,那么效率将会有很明显的下降
三,如何避免/减少回表
1.覆盖索引
如果我们想避免回表,那么我们就要让所查询字段出现在二级索引中,就比如我建立索引为idx_name_age(name,age),那么select name from user where age = 20就不会进行回表,索引的叶子节点就存储了id,name,age,直接返回就ok了
2.索引下推
这个功能是在MySQL5.6之后才出现的,索引下推(index condition pushdown)ICP将一些where条件下推到引擎层先进行过滤,再对过滤后的条件进行回表,没有通过的条件直接就不回表了,这样可以大大减少回表的次数
举个例子现在依旧一个索引idx_name_age(name,age),where name ='张%' and age = 20,如果没有ICP那么先查询到姓张的人的id,然后对这些人全部进行回表,回表后拿到的数据再进行age=20过滤,如果开启索引下推,那就会先找到name ='张%'的范围,然后再在索引叶子节点中找到过滤age=20这样就少回表不符合条件的了
3.减少select *的使用
使用这个select *基本上肯定要回表,所以就不要图方便随便使用这个select *
四,如何判断查询有没有回表
看Explain中的Extra值,如果是Using Index那么是覆盖索引,没有回表,如果是Using Index Conditiion,那么就是发生了ICP回表了,如果type值为Index,表示全索引扫描,不一定发生了回表
五,主键查询需要回表吗
不需要回表,主键索引的叶子节点中就包含整列数据,直接就可以查到不需要回表