理解回表查询

先理解什么是回表查询

定义:

回表查询(Table Lookup或Back to Table)是数据库查询中的一个过程,指在使用非聚集索引(Secondary Index或Non-Clustered Index)定位数据时,由于索引节点中不包含查询所需的全部列,数据库需要根据索引找到数据行的位置(通常是主键或行标识符),然后回到聚集索引或数据表中读取完整的数据行。

这种行为通常发生在查询的字段未被索引覆盖,索引不足以直接满足查询需求时,如果索引列无法完全满足查询字段,则数据库会通过索引找到记录位置后回表读取非索引列的数据。

当你需要查询的ID1列,没有在索引命中时,优化器会根据你根据索引查到的ID列的数据,再回到主表中,匹配完整的ID1的数据,这就是回表,如果ID的数据很多,就会造成回表的次数很多,消耗大量的磁盘IO,导致查询变慢

image

如何避免回表

如果你查的所有字段都能在某个辅助索引的叶子节点中被包含,那么就不需要回表

举个例子:

表 user(id, name, age, email)

create table "user"
(
id int,
name varchar(10),
age int,
email varchar(100)
);

我们建立了一个索引:KEY idx_name_age(name, age)

然后执行 SQL:

SELECT age from "user" where name='李小明';

1 #NSET2: [1, 1, 64]
2 #PRJT2: [1, 1, 64]; exp_num(2), is_atom(FALSE)
3 #SSEK2: [1, 1, 64]; scan_type(ASC), IDX_NAME_AGE(user), scan_range[('李小明',min),('李小明',max))

 

这时候:

  • 这个SQL命中了 idx_name_age 索引。
  • WHERE 和 SELECT 用到的字段(name和age)都在这个索引里。
  • 所以不需要去主键索引那里回表,直接从二级索引就能拿到数据。

这就是经典的覆盖索引命中。

 

但是如果你执行的是:

SELECT email from "user" where name='李小明';

 

1 #NSET2: [1, 1, 108]
2 #PRJT2: [1, 1, 108]; exp_num(2), is_atom(FALSE)
3 #BLKUP2: [1, 1, 108]; IDX_NAME_AGE(user)
4 #SSEK2: [1, 1, 108]; scan_type(ASC), IDX_NAME_AGE(user), scan_range[('李小明',min),('李小明',max))

 

抱歉,虽然WHERE条件命中了idx_name_age,但你要拿email,它不在这个索引的叶子节点中,只好通过name索引查到主键,然后回主键索引的B+树去拿整行数据。

 

总结什么样的索引需要回表,什么样的索引,不需要回

image

 

posted @ 2026-01-05 11:24  徐创业  阅读(2)  评论(0)    收藏  举报