MySQL回表机制解析与优化策略

一,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,表示全索引扫描,不一定发生了回表

五,主键查询需要回表吗

不需要回表,主键索引的叶子节点中就包含整列数据,直接就可以查到不需要回表

相关推荐
KIDULT°3 小时前
MySQL系列 (1):数据库原理
运维·数据库·mysql·云计算
我不是程序员三三3 小时前
透明加密软件偶发解密异常排错实录:文件时能打开时乱码
数据库·域智盾
snhna3 小时前
向量数据库深度实战:从 HNSW 到 pgvector、Milvus 选型与 RAG 落地
数据库·人工智能·python·postgresql·milvus
天行健,君子而铎4 小时前
数据分类分级的范式转换:从规则匹配到场景化高准确率一键部署
网络·数据库·安全
牛战士coding4 小时前
MySQL 读写分离完整链路:主从复制、多数据源与 @DS 路由
数据库·mysql
goehou5 小时前
MCP 查数实战:让 LLM 安全地查数据库(只读账号、SQL 校验、参数漂移)
数据库·ai·llm·教程·mcp·function calling
我不会插花弄玉5 小时前
7.函数【由浅入深-MySQL】
android·数据库·mysql
周小董6 小时前
[1369]Windows上安装PostgreSQL
数据库·windows·postgresql
一只积极向上的小咸鱼8 小时前
第一性原理思考:从拆解问题到用实验检验答案
数据库
这个DBA有点耶8 小时前
时序数据库InfluxDB高基数问题深度拆解:内存索引膨胀机制与OOM完整链路
数据库·架构·dba