目录

MySQL中的回表是什么

目录

MySQL中的回表是什么?

回表是指在使用 非聚簇索引(二级索引)进行查询时,若索引中未包含查询所需的全部数据,需要根据索引中的主键值回到聚簇索引(主键索引) 中查找完整数据行的过程。这一操作会增加额外的磁盘 I/O,可能对查询性能产生影响。 举一个例子。比如用户表,id是主键,name有索引。当执行SELECT * FROM users WHERE name=‘Arm’时,先通过name索引找到对应的id,再用id去主键索引里查整行数据。这时候就发生了两次索引查找,即回表。 https://i-blog.csdnimg.cn/direct/6f903f7c056d4155b7d628e864e1bb74.png select * from user where age = 20;需要根据二级索引(age)找到age = 20的主键键值,然后需要再根据主键去找整行的数据。主键索引频繁查询可能会造成大量随机I/O: 在磁盘上,数据是以数据页为单位进行存储和读取的。如果 age 为 20 的人很多,并且这些记录对应的主键 id 是无序且不连续的,那么在回表过程中,根据这些主键 id 到主键索引中查找记录时,就会需要频繁地访问不同的数据页。例如,一个 age 为 20 的记录对应的主键 id 是 10,下一个 age 为 20 的记录对应的主键 id 可能是 100,这两个 id 对应的记录很可能存储在不同的数据页上。磁盘在读取数据时,磁头需要移动到相应的位置才能读取数据。当需要频繁地访问不同的数据页时,磁头就需要不断地移动,这会带来大量的寻道时间和旋转延迟,也就是随机 I/O。与顺序 I/O 相比,随机 I/O 的性能要差很多,因为顺序 I/O 可以在一次磁头移动过程中连续读取多个数据页,而随机 I/O 每次都需要重新定位磁头,大大增加了磁盘 I/O 的开销。 举例: 假设 user 表中有如下部分数据:

idage
120
520
1520
2520
age 索引中可以快速找到 age 为 20 的记录对应的主键值
151525。但这些主键值在主键索引中对应的记录可能分散在不同的数据页上,例如 id 为 1 的记录在数据页 A,id 为 5
的记录在数据页 B,id 为 15 的记录在数据页 C,id 为 25 的记录在数据页 D。那么在回表时,就需要依次从数据页 A、B、C、D
中读取数据,这就导致了大量的随机 I/O。
所以当 age 为 20 的人很多且主键 id 无序不连续时,回表过程中主键索引的频繁查询会造成大量随机 I/O,从而影响查询性能。
如何避免回表:
可以使用覆盖索引
覆盖索引指索引包含查询所需的所有字段 ,无需回表即可返回结果:
 – 查询只需 name 和 age,建立联合索引 (name, age)
 CREATE INDEX idx_name_age ON users(name, age);
 ​
 – 执行以下查询时,无需回表
 SELECT name, age FROM users WHERE name = ‘张三’;
*避免使用 SELECT ,只选择必要的字段:
 – 避免回表
 SELECT id, name FROM users WHERE name = ‘张三’;
 ​
 – 需要回表(除非索引覆盖所有字段)
 SELECT * FROM users WHERE name = ‘张三’;
如何判断是否发生了回表
可以通过EXPLAIN命令查看执行计划,如果Extra列显示“Using index”,说明使用了覆盖索引