Using Where,Using index,Using index condition
创始人
2025-01-18 11:33:12
0

首先回顾一下这三个的定义

定义回顾

  • Using where
    当有where条件,但是不能使用索引或者使用索引后仍需扫描全表或者索引树判断条件的情况,简单来说,有效的where条件就Using where。
  • Using index
    索引覆盖,索引树已包含所有需要的数据,无需回表查询
  • Using index condition
    官方文档:https://dev.mysql.com/doc/refman/8.0/en/index-condition-pushdown-optimization.html
    索引条件下推(Index Condition Pushdown,ICP)是MySQL使用索引的情况的优化。
    简单来说,在服务器需要扫描表的情况下
    当没有ICP时,存储引擎扫描可以明确地使用索引的条件,将符合条件的记录返回给服务器。
    当使用ICP时,只要条件可以在索引上判断出来,就由存储引擎在索引树上完成判断,再将符合条件的记录返回给服务器。
    ICP可以减少存储引擎必须访问基本表的次数以及服务器必须访问存储引擎的次数,这是是否使用ICP的最可靠的判断条件

ICP有以下条件限制:

  • 当type为ref、eq_ref和ref_or_null且需要访问完整表行
  • InnoDB或MyISAM引擎
  • 对于InnoDB来说,ICP只适用于二级索引,可以减少全表扫描从而减少IO次数。对于聚集索引,数据和索引都已经在InnoDB缓冲池中,使用ICP不能减少IO操作。
  • 虚拟列上的二级索引不支持ICP
  • 子查询条件不能下推
  • 不能使用存储函数,存储引擎不能调用这些函数
  • 触发条件不能被下推

是否启用ICP
SET optimizer_switch = ‘index_condition_pushdown=off’;
SET optimizer_switch = ‘index_condition_pushdown=on’;

实战分析

数据库来自MySQL官方employees库

表结构如下:
MySQL8.0.19

CREATE TABLE `employees` (   `emp_no` int NOT NULL,   `birth_date` date NOT NULL,   `first_name` varchar(14) NOT NULL,   `last_name` varchar(16) NOT NULL,   `gender` enum('M','F') NOT NULL,   `hire_date` date NOT NULL,   PRIMARY KEY (`emp_no`),   KEY `index_all` (`birth_date`,`last_name`,`first_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 

birth_date, last_name, first_name三列联合索引,编码utf8

无条件覆盖索引

explain select emp_no, first_name, last_name from employees;  +----+-------------+-----------+------------+-------+---------------+-----------+---------+------+--------+----------+-------------+ | id | select_type | table     | partitions | type  | possible_keys | key       | key_len | ref  | rows   | filtered | Extra       | +----+-------------+-----------+------------+-------+---------------+-----------+---------+------+--------+----------+-------------+ |  1 | SIMPLE      | employees | NULL       | index | NULL          | index_all | 97      | NULL | 299423 |   100.00 | Using index | +----+-------------+-----------+------------+-------+---------------+-----------+---------+------+--------+----------+-------------+ 

type为index,扫描整个索引树,服务器层不需要再判断条件,所以Extra只有Using index
使用三列,key_len = 3 + (14 * 3 + 2) + (16 * 3 + 2) = 97

有条件覆盖索引

explain select emp_no, last_name from employees where birth_date = '1999-09-09';  +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+ | id | select_type | table     | partitions | type | possible_keys | key       | key_len | ref   | rows | filtered | Extra       | +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+ |  1 | SIMPLE      | employees | NULL       | ref  | index_all     | index_all | 3       | const |    1 |   100.00 | Using index | +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+ 

满足最左匹配原则,且非唯一索引,故type为ref,走覆盖索引,Using index
key_len = 3

不满足最左匹配

explain select emp_no, first_name from employees where last_name like '%达到%';  +----+-------------+-----------+------------+-------+---------------+-----------+---------+------+--------+----------+--------------------------+ | id | select_type | table     | partitions | type  | possible_keys | key       | key_len | ref  | rows   | filtered | Extra                    | +----+-------------+-----------+------------+-------+---------------+-----------+---------+------+--------+----------+--------------------------+ |  1 | SIMPLE      | employees | NULL       | index | NULL          | index_all | 97      | NULL | 299423 |    11.11 | Using where; Using index | +----+-------------+-----------+------------+-------+---------------+-----------+---------+------+--------+----------+--------------------------+ 

where条件不满足最左匹配,但是select的列在索引树中可以全部找到,故Using index,并且type为index,存储引擎扫描整个索引树,找到满足last_name like '%达到%'的数据(where条件有效),返回给服务器,服务器再过滤不需要的字段。
因为使用了整个联合索引,key_len = 97

如果select了不在联合索引的字段,则不能使用覆盖索引,只有Using where了。

索引下推

explain select emp_no, first_name, hire_date from employees where birth_date = '199-09-09'   and last_name like '%达到%';  +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+-----------------------+ | id | select_type | table     | partitions | type | possible_keys | key       | key_len | ref   | rows | filtered | Extra                 | +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+-----------------------+ |  1 | SIMPLE      | employees | NULL       | ref  | index_all     | index_all | 3       | const |    1 |    11.11 | Using index condition | +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+-----------------------+ 

首先明确一点,这条SQL必须访问基本表,因为有hire_date字段,所以一定没有Using index。
满足最左匹配,birth_date字段走索引,但是last_name不能走索引。
在有ICP的情况下,last_name的判断由存储引擎在索引树上完成,返回给服务器后,因为有hire_date字段,服务器访问基本表获取所有数据。

当没有ICP情况下,last_name由服务器完成判断,只有Using where,服务器读取基本表的部分行可能是不满足条件的。

注意:Using index condition下推的条件并没有用到索引,而是全部扫描,所以key_len不计算在内,所谓用到索引,就是利用了B+树查找的特性

+----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+ | id | select_type | table     | partitions | type | possible_keys | key       | key_len | ref   | rows | filtered | Extra       | +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+ |  1 | SIMPLE      | employees | NULL       | ref  | index_all     | index_all | 3       | const |    1 |    11.11 | Using where | +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+-------------+ 

去掉hire_date

explain select emp_no, first_name from employees where birth_date = '199-09-09'   and last_name like '%达到%';  +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+--------------------------+ | id | select_type | table     | partitions | type | possible_keys | key       | key_len | ref   | rows | filtered | Extra                    | +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+--------------------------+ |  1 | SIMPLE      | employees | NULL       | ref  | index_all     | index_all | 3       | const |    1 |    11.11 | Using where; Using index | +----+-------------+-----------+------------+------+---------------+-----------+---------+-------+------+----------+--------------------------+ 

没有hire_date,服务器不需要访问基本表,ICP优化也就没必要了。

相关内容

热门资讯

一分钟了解!丽水双扣茶苑脚本,... 一分钟了解!丽水双扣茶苑脚本,胡易决胜麻架辅助-好像真的是有辅助工具(竟然有挂)1、丽水双扣茶苑脚本...
网友热议!河南微乐小程序辅助器... 网友热议!河南微乐小程序辅助器免费!竟然存在有辅助软件(有挂实锤)小薇(辅助器软件下载)致您一封信;...
记者爆料!途游四川辅助器是真的... 记者爆料!途游四川辅助器是真的吗,789大菠萝辅助-本来是真的有辅助方法(有挂教程)1、完成途游四川...
玩家必用!花城棋舍插件安装!总... 玩家必用!花城棋舍插件安装!总是真的有辅助攻略(有挂方法)1.花城棋舍插件安装 选牌创建新账号,点击...
新手必备!琼崖海南麻将辅助器,... 新手必备!琼崖海南麻将辅助器,正宗牛总管辅助-一直是真的有辅助挂(有挂助手)1)琼崖海南麻将辅助器辅...
研究成果!赣湘互娱挂!好像真的... 研究成果!赣湘互娱挂!好像真的是有辅助挂(有挂详情)1、每一步都需要思考,不同水平的挑战会更加具有挑...
交流学习经验!赣南好友辅助,悠... 交流学习经验!赣南好友辅助,悠闲游戏辅助-确实是真的有辅助器(有挂讲解)1、赣南好友辅助模拟器是什么...
实测分享!广东雀神智能插件是真... 实测分享!广东雀神智能插件是真的!总是存在有辅助神器(确实有挂)广东雀神智能插件是真的脚本下载中分为...
总算清楚!微信游戏决胜游戏辅助... 您好,微信游戏决胜游戏辅助这款游戏可以开挂的,确实是有挂的,需要了解加去威信【136704302】很...
技术分享!欢乐联盟免费辅助!果... 技术分享!欢乐联盟免费辅助!果然是真的有辅助教程(了解有挂)技术分享!欢乐联盟免费辅助!果然是真的有...