• MySQL索引下推


    如果你在面试中,听到MySQL5.6”、“索引优化” 之类的词语,你就要立马get到,这个问的是“索引下推”。

    什么是索引下推

    索引下推(Index Condition Pushdown,简称ICP),是MySQL5.6版本的新特性,它能减少回表查询次数,提高查询效率

    索引下推优化的原理

    我们先简单了解一下MySQL大概的架构:

    MySQL服务层负责SQL语法解析、生成执行计划等,并调用存储引擎层去执行数据的存储和检索

    索引下推下推其实就是指将部分上层(服务层)负责的事情,交给了下层(引擎层)去处理

     具体

    我们来具体看一下,在没有使用ICP的情况下,MySQL的查询:

    • 存储引擎读取索引记录;

    • 根据索引中的主键值,定位并读取完整的行记录;

    • 存储引擎把记录交给Server层去检测该记录是否满足WHERE条件。

    使用ICP的情况下,查询过程:

    • 存储引擎读取索引记录(不是完整的行记录);

    • 判断条件部分能否用索引中的列来做检查,条件不满足,则处理下一行索引记录;

    • 条件满足,使用索引中的主键去定位并读取完整的行记录(就是所谓的回表);

    • 存储引擎把记录交给层,层检测该记录是否满足条件的其余部分。

    索引下推的具体实践

    理论比较抽象,我们来上一个实践。

    使用一张用户表tuser,表里创建联合索引(name, age)。

     如果现在有一个需求:检索出表中名字第一个字是张,而且年龄是10岁的所有用户。那么,SQL语句是这么写的:

    select * from tuser where name like '张%' and age=10;
    

     假如你了解索引最左匹配原则,那么就知道这个语句在搜索索引树的时候,只能用 ,找到的第一个满足条件的记录id为1。 因为

    对于联合索引mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配

    那接下来的步骤是什么呢?

    没有使用ICP

    在MySQL 5.6之前,存储引擎根据通过联合索引找到name likelike '张%' 的主键id(1、4),逐一进行回表扫描,去聚簇索引找到完整的行记录,server层再对数据根据age=10进行筛选

     这里有一个回表概念

    MySQL在InnoDB引擎下支持两种索引
    
    聚集索引 :索引里(B+树的叶子结点上)存储的是数据行(真实的数据)
    普通索引 :索引里(B+树的叶子结点上)存储的是主键
    这里着重说一下聚集索引,官方文档有以下描述
    
    在有主键的表,InnoDB将主键作为聚集索引
    没有主键的表,InnoDB使用第一个唯一索引作为聚集索引
    即没有主键也没有唯一索引时,MySQL将生成一个隐藏的6字节大小的row ID字段作为聚集索引
      MySQL通过普通索引没法一次性将数据拿全的情况下,通过普通索引获取主键值,再通过主键值到聚集索引中定位到记录,这个过程就叫回表。
    可以通过建立覆盖索引来减少回表,比如现在要通过身份证号查姓名,那就建立身份证号和姓名的联合索引(id,name),当查询时可以通过这个索引直接拿到姓名name得值,不再需要去聚集索引里查找了,这就是覆盖索引

    我们看一下示意图:

    可以看到需要回表两次,把我们联合索引的另一个字段age浪费了

    使用ICP

    而MySQL 5.6 以后, 存储引擎根据(name,age)联合索引,找到,由于联合索引中包含列,所以存储引擎直接再联合索引里按照age=10过滤。按照过滤后的数据再一一进行回表扫描。

    我们看一下示意图:

     可以看到只回表了一次。除此之外我们还可以看一下执行计划,看到Extra一列里 Using index condition,这就是用到了索引下推。

    +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
    | id | select_type | table | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra                 |
     
    | 1  | SIMPLE      | tuser | NULL       | range | na_index      | na_index | 102     | NULL | 2    | 25.00    | Using index condition |

    索引下推使用条件

    • 只能用于rangerefeq_refref_or_null访问方法;

    • 只能用于InnoDBMyISAM存储引擎及其分区表

    • 存储引擎来说,索引下推只适用于二级索引(也叫辅助索引);

    索引下推的目的是为了减少回表次数,也就是要减少IO操作。对于聚簇索引来说,数据和索引是在一起的,不存在回表这一说

    • 引用了子查询的条件不能下推

    • 引用了存储函数的条件不能下推,因为存储引擎无法调用存储函数

    问答区

    问题1 当复合索引列为(name,age,address)时 以下SQL能使用索引吗?

    select * from student where name like 'peng%' and age = 23;

    可以,遇到like会中断后续元素的匹配,但只能使用name这个字段,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配。范围列可以用到索引,但是范围列后面的列无法用到索引。即索引最多用于一个范围列,因此如果查询条件中有两个范围列则无法全用到索引。

    问题2 索引下推只能存在联合索引里吗?

    是的,非联合索引无法使用索引下推

    问题3 索引下推在哪些情况下无法使用?

    下推条件遇到子查询
    
    下推条件遇到函数
    
    非InnoDB表和MyISAM表

    问题4 索引下推如何开启和关闭?

    // 索引下推默认是开启的
    set optimizer_switch='index_condition_pushdown=off'; // 关闭
    set optimizer_switch='index_condition_pushdown=on'; // 开启

    总结

      索引下推在非主键索引上的优化,可以有效减少回表的次数,大大提升了查询的效率,在平时工作中可以根据业务情况通过优化索引来达到使用索引下推,提高业务吞吐量。

    索引下推(ICP)是针对MySQL使用索引从表中检索数据行的情况的优

    • 在没有索引下推的情况下,MySQL通过存储引擎遍历索引来定位表中的数据行并将它们返回给MySQl服务器,服务器再进行WHERE条件的判断,确认是否将数据行加入结果集。
    • 开启索引下推,且WHERE条件部分可以仅使用索引中的列来评估,这时MySQL服务器会将这部分WHERE条件下推到存储引擎,接着存储引擎使用索引条目评估推送的索引条件,仅当满足该条件时才从表中进行读取

    索引下推可以减少存储引擎访问数据表的次数以及MySQL服务器访问存储引擎的次数。

  • 相关阅读:
    JVM 体系结构
    字符集和编码
    Thinking in Java 笔记
    HSDB
    jdb
    JVM-Class文件
    JVM-操作码助记符
    表、栈和队列
    算法分析
    Shell 编程
  • 原文地址:https://www.cnblogs.com/cy0628/p/16366561.html
Copyright © 2020-2023  润新知