回表

回表

1. 回表

简单说就是mysql内部需要经过两次查询,第一次先索引扫描,然后再通过主键去取索引中未能提供的数据。

  • 就是数据库根据索引找到了指定的记录所在行后,还需要根据rowid再次到数据块里取数据的操作。
  • 比如这样的执行计划,先索引扫描,再通过rowid去取索引中未能提供的数据,即为回表。
  • “回表”一般就是指执行计划里显示的“TABLE ACCESS BY INDEX ROWID”
  • 再例如,虽然只查询索引里的列,但是需要回表过滤掉其他列。

怎么避免回表?
将需要的字段放在索引中去。查询的时候就能避免回表。但是不要刻意去避免回表,那样代价太了。也不是将所有的字段都放在所有中。

实例

 create `table` tb_name(
`id` int(11) not null auto_increment , 
`k` int(11) default '0' ,
`name` varchar(16),
primary key(id)
index (k)
)engine=InnoDB;

我们提取id=500这一行的全部数据,这里通过主键id定位到这一行,然后返回数据

select * from T where ID=500;
+-----+---+-------+
| id  | k | name  |
+-----+---+-------+
| 500 | 5 | name5 |
+-----+---+-------+

这里我们先通过普通索引,搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程即为回表。

select * from T where k=5;
+-----+---+-------+
| id  | k | name  |
+-----+---+-------+
| 500 | 5 | name5 |
+-----+---+-------+

2.术语解释:

主键索引树(B+树)的叶子节点直接就是我们要查询的整行数据,而非主键索引的叶子节点是主键的值,查到主键的值以后,还需要再通过主键的值再进行一次查询。

问题来了,刚才我们知道了主键索引查询只会查一次,而非主键索引需要回表查询多次。那么,非主键索引一定会查询多次吗?
这就轮到我们的覆盖索引登场了~~

覆盖索引
覆盖索引(covering index)指一个查询语句的执行结果只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。 当一条查询语句符合覆盖索引条件时,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率。
如,表covering_index_sample中有一个普通索引 idx_key1_key2(key1,key2)。
当我们通过SQL语句:select key2 from covering_index_sample where key1 = ‘keytest’;的时候,就可以通过覆盖索引查询,无需回表。

3.怎么判定是否出现了回表

  • Extra中看到了Using where,代表是按照where条件进行了过滤,和是否走索引、回表无必然的关系。
  • Extra中是using index & using
    where,表示select的数据在索引中能找到,但需要根据where条件过滤,这种情况也不回表。
  • 只有在使用了索引,且Extra是Using where的情况下,才代表回表查询数据

摘自:https://blog.youkuaiyun.com/xjh163/article/details/100076904

### 三级标题:MySQL回表的概念及工作机制 #### 什么是MySQL回表? 在MySQL中,**回表(Back to Table)**是指当查询使用非聚簇索引(二级索引)进行查找时,最终需要到主键索引(聚簇索引)所在的数据中获取完整记录的过程。由于InnoDB存储引擎的**聚簇索引**直接关联实际的数据行,而非聚簇索引仅包含主键值和索引列的信息,因此在某些查询场景下,必须通过主键再次访问数据页以获取所有字段数据[^1]。 #### 回表的工作机制 在InnoDB中,每张都有一个**聚簇索引(通常是主键索引)**,它决定了数据的物理存储顺序。而**非聚簇索引**(如普通索引或唯一索引)则单独存储,并且其叶子节点保存的是对应记录的主键值。当执行查询时,如果查询条件涉及的字段没有全部包含在当前使用的索引中,则数据库需要先通过非聚簇索引找到主键值,然后通过主键值去聚簇索引中查找完整的数据记录,这个过程即为“回表”操作[^1]。 例如,假设有一个用户`users`,其主键为`user_id`,并建立了一个非聚簇索引在`email`字段上。若执行如下SQL语句: ```sql SELECT * FROM users WHERE email = 'test@example.com'; ``` 此时,数据库首先会使用`email`上的索引定位到对应的主键值,然后再根据该主键值到聚簇索引中查找所有字段的数据。这便是典型的回表操作。 #### 覆盖索引与回表优化 为了减少回表操作带来的性能开销,可以使用**覆盖索引(Covering Index)**。覆盖索引指的是查询所需的所有字段都包含在一个索引中,这样数据库可以直接从索引中获取数据而无需再访问中的数据页。例如,若执行以下SQL语句: ```sql SELECT user_id FROM users WHERE email = 'test@example.com'; ``` 在这种情况下,如果`email`索引已经包含了`user_id`字段(或者是一个组合索引),则不需要进行回表操作,因为所需的字段已经在索引中找到。 #### 回表的性能影响 回表操作会导致额外的I/O访问,尤其是在数据量较大、索引设计不合理的情况下,性能下降会更加明显。因此,在数据库优化过程中,应尽量避免不必要的回表操作。可以通过分析执行计划(如`EXPLAIN`语句)来判断是否发生了回表,并据此调整索引策略。 --- #### 相关问题 1. 如何判断一个查询是否发生了回表? 2. 什么是覆盖索引?它如何帮助减少回表操作? 3. 在设计索引时,如何避免不必要的回表? 4. MySQL的执行计划中哪些信息可以反映回表的存在? 5. 为什么在使用非聚簇索引时,回表是不可避免的?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值