MySQL回表、索引覆盖、索引下推

准备

创建一张表,并创建一个自增主键索引和一个组合索引

CREATE TABLE index_opt_test (
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(11) DEFAULT NULL,
  title varchar(11) DEFAULT NULL,
  age int(11) DEFAULT NULL,
  sex varchar(11) DEFAULT NULL,
  content varchar(500) DEFAULT NULL,
  PRIMARY KEY (id),
  KEY idx_cb (name,title,age)
) ENGINE=InnoDB;

回表

  1. 什么是回表

    回表是发生在二级索引上的一种数据查询操作,简单点讲就是我们要查询的列不在二级索引的列中,那么就必须根据二级索引查到主键ID,然后再根据主键ID到聚簇索引树上去查询整行的数据,这一过程就叫作回表。

  2. 为什么会回表

    写一个会回表查询的SQL:

    select id, name, age, sex from index_opt_test where name='cc' and title='T7' and age=35;
    

    解析:

    ​ SQL需要查询的列包括id、name、age、sex,查询条件命中索引idx_cb,其中列id、name、age都在索引idx_cb中可以获取到,但是sex不能通过索引获取到,必须要获取到整行数据之后再从结果中捞出来sex列的数据,这种情况就必须要回表。

  3. 什么情况下不需要回表

    当所有的列都能在二级索引树中查询到,就不需要再回表了,这种情况就是索引覆盖。

索引覆盖

  1. 什么是索引覆盖

    当SQL语句中查询的列都在索引中时,我们就不需要回表去把整行数据都捞出来了,可以从非聚簇索引树中直接获取到我们需要的列的数据,这就叫索引覆盖。简单点来讲就是:所有不需要回表的查询操作都叫索引覆盖。

  2. 为什么会发生索引覆盖

    关于为什么会发生索引覆盖这个问题,通过一条SQL来理解:

    select id, name, age from index_opt_test where name='cc' and title='T7';
    

    这条SQL要查询的列id、name、age全部都能从非聚簇索引idx_cb中直接查询出来,可能会有个疑问:我们的索引列是name、title和age,为什么id明明不在组合索引中却还能发生索引覆盖?提出这个问题的同学真的是欠我一顿小烧烤,非聚簇索引的叶子节点里存的是什么东西:主键的关键字啊,我们这里主键是id,他的关键字就是id的值啊,那我们通过非聚簇索引是不是可以直接将主键id查出来,是不是就不用再回表了,不用回表是不是就发生了索引覆盖啊,就是那么简单。

索引下推

  1. 什么是索引下推

    索引下推又叫索引条件下推(Index Condition Pushdown,简称ICP),ICP默认是开启的,使用ICP可以减少存储引擎访问基础表的次数和Server访问存储引擎的次数。

    • ICP没有启用:Server层会根据索引的断桥原则将命中的索引字段推送到引擎层获取数据,并把匹配到的数据全部返回到Server层,由Server层再根据剩余的where条件进行过滤,即使where条件中有组合索引的其他未命中的字段,也会保留在Server层做筛选,然后返回给Client

      select id, name, sex from index_opt_test where name='cc' and title like '%7' and sex='male';
      

      执行过程:

      1. Server层把name推到引擎层

        1. 引擎层根据name去idx_cb的索引树中匹配主键
        2. 回表去捞数据返回给Server层
        3. Server层再根据title、sex筛选出最终的数据
        4. 最后返回给客户端

      image-20200410003327016

    • ICP启用:Server层会将where条件中在组合索引中的字段全部推送到引擎层,引擎层根据断桥原则匹配出索引数据,然后将其他索引字段带入再进行一次筛选,然后拿最终匹配的主键关键字回表查询出数据后返回给Server层,Server层再根据剩余的where条件做一次筛选,然后返回给Client

      select id, name, sex from index_opt_test where name='cc' and title like '%7' and sex='male';
      

      执行过程:

      1. Server把name和title都推到引擎层

        1. 引擎层根据name去idx_cb中查询出主键关键字和title、age
        2. 再由title筛选出匹配的主键关键字
        3. 回表去捞数据返回给Server层
        4. Server层再根据sex筛选出最终的数据
        5. 再返回给客户端

      image-20200410003348304

  2. 索引下推适用条件

    • ICP 用于访问方法是 range/ref/eq_ref/ref_or_null,且需要访问表的完整行记录。
    • ICP适用于 InnoDB 和 MyISAM 的表,包括分区的表。
    • 对于 InnoDB 表,ICP只适用于二级索引。ICP 的目标是减少访问表的完整行的读数量从而减少 I/O 操作。对于 InnoDB 的聚簇索引,完整的记录已经读进 InnoDB 的缓存,使用 ICP 不能减少 I/O 。
    • ICP 不支持建立在虚拟列上的二级索引(InnoDB 支持在虚拟列上建立二级索引)。
    • 引用子查询、存储函数的条件没法下推,Triggered conditions 也没法下推。

    所以ICP 适用的一个隐含前提是二级索引必须是组合索引、且在使用索引进行扫描时只能采用最左前缀匹配原则。组合索引后面的列出现在 where 条件里,因此可以先过滤索引元组、从而减少回表读的数量。

  3. 为什么会发生索引下推

    索引下推在5.6版本加入的,默认开启,可以通过命令SHOW VARIABLES like '%optimizer_switch%'查看当前状态

    image-20200410001946545
    • 关闭索引下推

      SET optimizer_switch = 'index_condition_pushdown=off';
      

      执行之后查看一下状态:

      image-20200410002144781

      然后我们执行一下SQL语句:

      explain
      select id, name, sex from index_opt_test where name='cc' and title like '%7' and sex='male';
      

      image-20200410002324446

      从执行计划我们可以看出当我们关闭索引下推后,Extra中的是Using where

    • 开启索引下推

      SET optimizer_switch = 'index_condition_pushdown=on';
      

      执行之后查看一下状态:

      image-20200410001946545

      然后我们执行以下SQL语句:

      explain
      select id, name, sex from index_opt_test where name='cc' and title like '%7' and sex='male';
      

      image-20200410002808326

      从执行计划中看到使用了Using index conditionUsing whereUsing index condition说明ICP生效了,title被推到了引擎层,而Using where是因为where条件中的sex字段

<think>好的,我现在需要解释MySQL中的“索引命中”、“索引”和“索引下推”这三个概念。首先,我得确保自己正确理解每个术语的含义,然后组织语言用中文清晰地达出来,同时遵循用户提供的格式要求,比如行内公式用$...$,独立公式用$$...$$,并且结构要清晰。 首先,索引命中。这应该是指当执行查询时,MySQL能够利用索引来快速定位数据,而无需全扫描。比如,如果有一个索引在name字段上,查询条件WHERE name = 'Alice'就会命中这个索引。需要说明索引的结构,比如B+树,以及如何通过索引快速查找数据行。 接下来是索引。当查询的列不在索引中时,即使命中索引MySQL还需要根据索引中的主键值到主键索引(聚簇索引)中查找完整的行数据。这个过程称为。例如,索引是(name),但查询需要获取age,这时候就需要。这里可能需要提到覆盖索引的概念,即如果索引包含所有需要的字段,就可以避免。 然后是索引下推(Index Condition Pushdown,ICP)。这是在MySQL 5.6引入的优化技术,允许在存储引擎层提前过滤不符合条件的行,减少次数。比如,查询条件WHERE name LIKE 'A%' AND age > 20,如果索引在(name, age)上,在没有ICP的情况下,存储引擎会先找到所有name以A开头的主键,然后获取age再过滤。而有了ICP,存储引擎会直接在索引中检查age条件,减少的数据量。需要解释ICP的作用和如何提升性能。 接下来需要考虑如何将这些内容结构化,分点说明,每个部分可能还需要例子或场景说明。同时注意用户提到的格式要求,行内数学达式比如索引结构可能需要用LaTeX,例如B+树的高度$h$,查找复杂度$O(\log n)$等。不过根据用户给的例子,可能不需要太复杂的公式,所以这里可能需要酌情处理。 需要检查是否有遗漏的关键点,比如索引的结构、的原因、覆盖索引、ICP的工作原理和版本支持。同时确保语言通俗易懂,避免技术术语堆砌,但又要准确。可能还需要对比有无ICP的情况下的执行流程差异,以突出其优化效果。 最后,确保答符合用户的结构要求:分点解释每个概念,可能包括定义、原理、示例、影响或优化建议。同时使用中文,避免Markdown格式,但保持段落清晰,可能用序号或标题来分隔各个部分。同时注意LaTeX的正确使用,比如行内公式用$...$,独立公式如果需要的话用$$...$$,但根据用户的问题,可能不需要太多公式,主要是在解释索引结构或查询过程时可能需要。 总结一下,答的结构大致如下: 1. 索引命中 - 定义:查询条件使用索引快速定位数据 - 原理:B+树结构,减少扫描行数 - 示例:WHERE子句使用索引列 - 注意点:最左前缀原则,索引选择性 2. 索引 - 定义:需要主键索引取数据 - 原理:二级索引存储主键值 - 示例:查询列不在索引中 - 优化:覆盖索引 3. 索引下推 - 定义:存储引擎层提前过滤 - 原理:在索引遍历时应用WHERE条件 - 示例:组合索引,部分条件在索引中处理 - 优势:减少次数,提升性能 在写作过程中,需要检查每个部分是否准确,是否有错误。例如,索引下推是否仅适用于组合索引,还是单列索引也可以?实际上,ICP适用于索引能够覆盖的列,不管是否是组合索引,但通常组合索引更能体现其优势。另外,需要确认MySQL版本支持情况,ICP从5.6开始支持。 可能还需要提到执行计划中的Using index condition来示ICP的使用,而Using index示覆盖索引。这些细节能帮助用户更好地理解如何诊断和优化查询。 最后,确保语言流畅,逻辑清晰,符合用户的要求,分点讲解,帮助用户逐步理解这三个概念。</think>### MySQL索引命中索引索引下推详解 #### 一、索引命中 1. **定义** 当查询条件**完全或部分匹配索引结构**时,MySQL可通过索引快速定位数据,避免全扫描。例如: ```sql SELECT * FROM users WHERE name = 'Alice'; -- 若name字段有索引,则命中 ``` 2. **原理** - 索引通常采用$B^+$树结构,树高$h$决定查询复杂度为$O(\log n)$。 - **最左前缀原则**:联合索引$(a, b, c)$只能按$a$ → $a+b$ → $a+b+c$的顺序使用。 - **索引选择性**:唯一性高的字段(如ID)更适合建索引。 3. **示例** - 命中:`WHERE a=1 AND b=2`(联合索引$(a,b)$) - 未命中:`WHERE b=2`(未从最左字段$a$开始) --- #### 二、索引 1. **定义** 当索引**未覆盖查询所需全部列**时,需根据索引中的主键值**主键索引(聚簇索引)**获取完整行数据。 2. **原理** - 二级索引(如`INDEX(name)`)仅存储主键值。 - 若查询需获取`age`字段(未包含在索引中),流程如下: ```sql 1. 通过二级索引找到name='Alice'对应的主键id=100 2. 主键索引查找id=100的行,获取age=25 ``` 3. **优化:覆盖索引** 将查询列全部加入索引,例如: ```sql CREATE INDEX idx_name_age ON users(name, age); SELECT age FROM users WHERE name = 'Alice'; -- 无需 ``` --- #### 三、索引下推(ICP,Index Condition Pushdown) 1. **定义** MySQL 5.6+引入的优化技术,**将WHERE条件过滤提前到存储引擎层执行**,减少次数。 2. **原理** - **无ICP**:存储引擎仅按索引最左前缀筛选数据,剩余条件由Server层处理。 - **有ICP**:存储引擎直接利用索引中的字段过滤数据,减少传递给Server层的数据量。 3. **示例** ```sql -- 结构:INDEX(name, age) SELECT * FROM users WHERE name LIKE 'A%' AND age > 20; ``` - **无ICP**:先找到所有`name LIKE 'A%'`的主键,后由Server层过滤`age > 20`。 - **有ICP**:存储引擎在索引中直接过滤`name LIKE 'A%' AND age > 20`,仅符合条件的主键。 4. **优势** - 减少次数,降低I/O开销。 - 执行计划显示`Using index condition`即示触发ICP。 --- ### 总结对比 | 概念 | 触发场景 | 优化目标 | 关键标志 | |------------|------------------------------|-------------------|-----------------------| | 索引命中 | 查询条件匹配索引结构 | 减少扫描行数 | `Using index` | | 索引 | 查询列未完全被索引覆盖 | 避免 | 无 | | 索引下推 | WHERE条件可被索引部分覆盖 | 减少次数 | `Using index condition` | 通过合理设计索引(如覆盖索引、联合索引)和利用ICP,可显著提升查询性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值