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、下载好如何下载科乐填大坑...
8分钟妙招!长春科乐天天踢辅助... 8分钟妙招!长春科乐天天踢辅助(外挂)本来有辅助神器(哔哩哔哩)8分钟妙招!长春科乐天天踢辅助(外挂...
5分钟了解!pokemmo脚本... 5分钟了解!pokemmo脚本辅助器(脚本)总是真的有辅助神器(哔哩哔哩)pokemmo脚本辅助器辅...
经核实!福建天天开心作必弊&q... 经核实!福建天天开心作必弊"真是存在有辅助教程"(哔哩哔哩)1、经核实!福建天天开心作必弊"真是存在...
9分钟了解!cloudpoke... 9分钟了解!cloudpoker怎么开挂(脚本)都是存在有辅助方法(哔哩哔哩)1、cloudpoke...
十分钟窍门!友友联盟免费辅助器... 十分钟窍门!友友联盟免费辅助器app(外挂)切实是真的有辅助技巧(哔哩哔哩)1、友友联盟免费辅助器a...
日前!衢州都莱罗松辅助器&qu... 日前!衢州都莱罗松辅助器"果然存在有辅助神器"(哔哩哔哩)1、每一步都需要思考,不同水平的挑战会更加...
6分钟了解!wepokerpl... 6分钟了解!wepokerplus万能挂(脚本)切实是真的辅助方法(哔哩哔哩)1、完成wepoker...
第8分钟方针!爱游辅助app(... 第8分钟方针!爱游辅助app(外挂)切实真的有辅助教程(哔哩哔哩)1、这是跨平台的爱游辅助app轻量...
2026版辅助挂!天天开心国王... 2026版辅助挂!天天开心国王辅助"切实是真的有辅助app"(哔哩哔哩)1、天天开心国王辅助辅助器安...