mysql 回表 覆盖索引_回表与覆盖索引

正式讲 ICP 之前了,我们先将相关的概念捋一捋,知道的就当回顾,不知道的就当了解了,这有助于对 ICP 的理解

建个示例表 tbl_index

CREATE TABLE tbl_index (

c1 INT,

c2 INT,

c3 CHAR(1),

PRIMARY KEY(c1),

KEY idx_c2 (c2)

);

覆盖索引

如果 where 条件的列和 select 的列都在一个索引中,通过这个索引就可以完成查询,这就叫就叫覆盖索引;当然,覆盖索引基本针对的是组合索引(InnoDB 的聚簇索引有点特殊,具体可以看下面的图)

针对上面的 tbl_index, select c2 from tbl_index where c2 = 4; 是覆盖索引查询,但是这条 SQL 没有意义,如果我们在 tbl_index 表上增加索引 index idx_c2_c3 (c2,c3) ,那么 select c3 from tbl_index where c2 = 4; 走覆盖索引查询还是很有意义的,那问题又来了,覆盖索引的意义何在 ? 我们往下看

回表

通过某个索引无法直接完成 SQL 查询(where 条件的列和 select 的列不全部存在于任何一个索引中),那么此时需要获取完整的数据记录来完成此次查询,从索引项记录到获取对应的完整数据记录的过程就叫回表;概念可能说的有些抽象,我们结合 MySQL 来看看具体什么是回表

InnoDB 的回表

InnoDB 的索引结构有些特殊,非聚簇索引(二级索引)回表到聚簇索引的过程类似如下

184962022_1_20200309080207581.png

InnoDB的聚簇索引即数据,索引和数据是存在一起的;那么直接走聚簇索引查询的 SQL 是不存在回表一说的,比如 select* from tbl_index where c1 = 10; ,只有从二级索引出发,并且二级索引独自完成不了查询的时候才会回表到聚簇索引完成查询

MyISAM 的回表

有这样一种说法: MyISAM 中的索引都是二级索引 ,其实说的是聚簇索引和二级索引的结构基本一致,只是聚簇索引有个唯一性约束

MyISAM 聚簇索引和二级索引,以及它们的回表过程类似如下

184962022_2_2020030908020866.png

MyISAM 的回表过程指的是根据叶子节点中的数据记录的地址来获取完整记录的过程,无论是聚簇索引还是二级索引都可能存在回表的过程;MyISAM 的回表与 InnoDB 还是有差别的

无论是 InnoDB 的回表还是 MyISAM 的回表,很有可能会造成额外的磁盘 IO,这会严重影响查询效率,覆盖索引的目的就是尽量能够一次完成 SQL 查询,避免有回表过程,从而提高效率

如何确认 MySQL 是进行了覆盖索引查询,还是进行了回表查询 ?

看 MySQL 的执行计划,如果 Extra 中只有 using index 则说明使用了覆盖索引查询,如果 Extra 中出现了 using indexcondition 或 using index & using where 则说明进行了回表查询

ICP

Index Condition Pushdown,MySQL 5.6 中引入的一种优化策略

那么究竟是将什么从哪 Push Down 到哪,优化了什么?要弄清楚这 4 个问题,我们需要先弄清楚 where 条件的提取与应用,具体可查看:神奇的 SQL 之 WHERE 条件的提取与应用

where 条件会被提取成 3 部分: Index Key,Index Filter,Table Filter ,在 MySQL 5.6 之前,并不区分 Index Filter 与 Table Filter,统统将 Index First Key 与 Index Last Key 范围内的索引记录,回表读取完整记录,然后返回给 MySQL Server 层进行过滤,而在 MySQL 5.6 之后,Index Filter 与 Table Filter 分离,Index Filter 下降到引擎层(InnoDB和MyISAM)的索引层面进行过滤,减少了回表与返回 MySQL Server 层的记录交互开销,提高了 SQL 的执行效率

ICP 优化过程

假设我们有表: tbl_icp

184962022_3_20200309080208425.gifcreate table tbl_icp (a int primary key, b int, c int, d int, e varchar(50));create index idx_bcd on tbl_icp(b, c, d);insert into tbl_icp values (4,3,1,1,'a');insert into tbl_icp values (1,1,1,2,'d');insert into tbl_icp values (8,8,7,8,'h');insert into tbl_icp values (2,2,1,2,'g');insert into tbl_icp values (5,2,2,5,'e');insert into tbl_icp values (3,3,2,1,'c');insert into tbl_icp values (7,4,0,5,'b');insert into tbl_icp values (6,5,2,4,'f');

若没有使用 ICP,则 SQL 查询类似如下

184962022_4_20200309080208581.png

没有使用 ICP 时,引擎层会将满足 Index Key 范围限制的所有数据记录(示例中一共 6 条)逐条返回给 Server 层,然后由 server 层应用 Index Filter 和 Table Filter (MySQL 5.6 之前不区分 Index Filter 和 Table Filter),最后将满足条件的数据返回给客户端;

若使用 ICP,则 SQL 查询类似如下

184962022_5_20200309080208878.png

使用了 ICP,Server 层会将 Index Filter 下推到引擎层,引擎层在对 Index First Key 与 Index Last Key 范围内的索引项逐条进行过滤的时候,会应用上 Index Filter,对不满足 Index Filter 条件的索引项直接过滤掉,无需回表操作,也无需返回给 Server 层,从而提供执行效率;上图中的索引项: 3 1 1 、 3 2 1 不满足 Index Filter 中的 d != 1 , 4 0 5 不满足 c > 0 ,所以这 3 个索引项无需进行回表操作,也不需要返回给 Server 层

相信到这里,大家对 ICP 的 4 个问题应该就比较清楚了

ICP 的适用条件

虽说 ICP 能提高 SQL 执行效率,但也不是任何情况下都适用的,它只适用于某些情况

1、当 SQL 需要全表访问时,ICP 的优化策略可用于 range, ref, eq_ref,  ref_or_null 类型的数据访问方式

2、只适用于 InnoDB 和 MyISAM 两种存储引擎

3、在 InnoDB 中,ICP 只适用于二级索引

ICP 的目的就是为了减少回表导致的磁盘 I/O,而 InnoDB 的聚簇索引的叶子节点存放的就是完整的数据记录,只要索引数据被读到内存了,那么索引项对应的完整数据记录也就读到内存了,那么通过索引项获取数据记录的过程就在内存中进行了,无需进行磁盘 I/O;也就说聚簇索引上应用 ICP,不会减少磁盘 I/O,也就没有使用的意义了

4、不支持覆盖索引

其实和第 3 点一样,因为覆盖索引无需回表,ICP 也就没意义了

5、不支持子查询条件的下推

6、不支持存储过程条件、触发器条件的下推

至于 ICP 的优化效果,取决于在存储引擎内通过 ICP 筛选掉的数据的比例,过滤掉的数据比例大,那就性能提升大,反之则性能提升小

总结

1、索引覆盖与回表

这两个往往是一起来考虑的,因为覆盖索引的目的就是减少因回表产生的磁盘 I/O,从而提高执行效率

在实际应用中,我们往往也需要考虑尽可能用覆盖索引来完成我们的 SQL 查询

2、ICP的四个问题

将什么从哪 Push Down 到哪,优化了什么

将 Index Filter 从 Server 层 Push Down 到了引擎层,减少了因回表产生的磁盘 I/O,也减少了与 Server 层的交互,提高了 SQL 执行效率

3、疑问点

为什么这么明显的优化策略到 MySQL 5.6 才引入,个人感觉很容易就能考虑到呀,MySQL 的开发者们是肿么肥事 ?来源:https://www.icode9.com/content-4-654201.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回表查询是指在数据查询过程中,MySQL内部需要两次查询。首先,根据查询条件定位到查询数据所在表的主键值,然后再根据主键值定位到具体的行记录。这种查询方式需要额外的IO开销,对查询性能有一定的影响。 覆盖索引是指索引中包含了查询语句需要查询的所有字段,不需要再去读取数据行。当查询语句只需要查询索引中的字段时,MySQL可以直接从索引中获取到查询结果,而不需要再去读取数据行,大大提高了查询性能。 要判断是否发生了回表查询,可以通过执行计划(explain)中的Extra列来判断。如果在Extra中看到Using Where或者Extra为null的情况,代表发生了回表查询。而如果在Extra中看到Using Index & Using Where,则表示查询的数据可以在索引中找到,但还需根据where条件进行过滤,不会发生回表查询。 综上所述,回表查询是指MySQL在查询数据时需要额外定位行记录的查询方式,而覆盖索引是指索引中包含了所有需要查询的字段,不需要再去读取数据行。通过执行计划可以判断是否发生了回表查询。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【MySQL回表覆盖索引](https://blog.csdn.net/ccw_922/article/details/124650786)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [mysql回表查询和索引覆盖](https://blog.csdn.net/ywl470812087/article/details/128075298)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值