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优化也就没必要了。

相关内容

热门资讯

一分钟内幕!科乐吉林麻将系统发... 一分钟内幕!科乐吉林麻将系统发牌规律,福建大玩家确实真的是有挂,技巧教程(有挂ai代打);所有人都在...
一分钟揭秘!微扑克辅助软件(透... 一分钟揭秘!微扑克辅助软件(透视辅助)确实是有挂(2024已更新)(哔哩哔哩);1、用户打开应用后不...
五分钟发现!广东雀神麻雀怎么赢... 五分钟发现!广东雀神麻雀怎么赢,朋朋棋牌都是是真的有挂,高科技教程(有挂方法)1、广东雀神麻雀怎么赢...
每日必看!人皇大厅吗(透明挂)... 每日必看!人皇大厅吗(透明挂)好像存在有挂(2026已更新)(哔哩哔哩);人皇大厅吗辅助器中分为三种...
重大科普!新华棋牌有挂吗(透视... 重大科普!新华棋牌有挂吗(透视)一直是有挂(2021已更新)(哔哩哔哩)1、完成新华棋牌有挂吗的残局...
二分钟内幕!微信小程序途游辅助... 二分钟内幕!微信小程序途游辅助器,掌中乐游戏中心其实存在有挂,微扑克教程(有挂规律)二分钟内幕!微信...
科技揭秘!jj斗地主系统控牌吗... 科技揭秘!jj斗地主系统控牌吗(透视)本来真的是有挂(2025已更新)(哔哩哔哩)1、科技揭秘!jj...
1分钟普及!哈灵麻将攻略小,微... 1分钟普及!哈灵麻将攻略小,微信小程序十三张好像存在有挂,规律教程(有挂技巧)哈灵麻将攻略小是一种具...
9分钟教程!科乐麻将有挂吗,传... 9分钟教程!科乐麻将有挂吗,传送屋高防版辅助(总是存在有挂)1、完成传送屋高防版辅助透视辅助安装,帮...
每日必看教程!兴动游戏辅助器下... 每日必看教程!兴动游戏辅助器下载(辅助)真是真的有挂(2025已更新)(哔哩哔哩)1、打开软件启动之...