衡量一个SQL语句的表现的方式,你们都知道使用EXPLAIN
语句,字段想必你们也知道,可是经过实例我以为仍是更好理解。本文不会对每一个字段进行过多地赘述,网上不少大神比我总结得好。本文基于LIKE与正则表达式的实例在EXPLAIN
的表现。html
在分析SQL语句执行时,主要用到的列,分别为type
、Extra
,下文的测试用例均为官网提供的sakila
数据库,附上下载连接。mysql
film
表的状况以下,其实只须要idx_title
索引: 正则表达式
MySQL版本为:8.0+sql
ps:能够结合这篇文章看,这篇算做补充吧。数据库
title
来匹配相应的电影,从最简单的=
开始。rows
有可能不许确。filtered
:The filtered column indicates an estimated percentage of table rows that will be filtered by the table condition.The maximum value is 100, which means no filtering of rows occurred. Values decreasing from 100 indicate increasing amounts of filtering. rows shows the estimated number of rows examined and rows × filtered shows the number of rows that will be joined with the following table. For example, if rows is 1000 and filtered is 50.00 (50%), the number of rows to be joined with the following table is 1000 × 50% = 500.译文:是一个多少行会被表条件过滤的百分比估计值,通常与
rows
列结合着看,filtered × rows
就是被表条件过滤掉的行数。bash
=
explain select title from film where title= 'ACE GOLDFINGER';
复制代码
type
为ref
,使用的key
为idx_title
,实际使用索引与'ACE GOLDFINGER'
比较(即ref
=CONST
,因为使用索引查找与常量匹配(读取的行数rows
为1
),因为是使用覆盖索引,没有回表获取数据行,Extra
就是Using index
。id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | film | NULL | ref | idx_title | idx_title | 767 | const | 1 | 100.00 | Using index |
explain select * from film where title= 'ACE GOLDFINGER';
复制代码
Extra
就是NULL
。id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | film | NULL | ref | idx_title | idx_title | 767 | const | 1 | 100.00 | NULL |
LIKE
LIKE
语句的关键之一就在于%
位置,就分析下如下4种状况。explain select title from film where title LIKE 'A%';
复制代码
type
和Extra
:一、
type
:这里把LIKE
当成了一个有限制的索引扫描, 不用遍历全部索引,例如,索引BETWEEN 1 AND 100
的效果。 二、读取了46行数据 三、Extra
:Using where; Using index
这两个值同时在一块儿,究竟是什么意思呢?先卖个关子,后续详细说~post
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | film | NULL | range | idx_title | idx_title | 767 | NULL | 46 | 100.00 | Using where; Using index |
explain select * from film where title LIKE 'A%';
复制代码
Extra
:Using index condition
,后面详细说,其余字段倒和前一个语句没区别id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | film | NULL | range | idx_title | idx_title | 767 | NULL | 46 | 100.00 | Using index condition |
explain select title from film where title LIKE '%A';
复制代码
结果及分析: 一、首先,不是有限的索引查找,而是使用索引查询全表,因此type
是index
。 二、读取了1000行,过滤了1000 * 11.11的行数。性能
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | film | NULL | index | null | idx_title | 767 | NULL | 1000 | 11.11 | Using where; Using index |
explain select * from film where title LIKE '%A';
复制代码
Using where
:存储引擎检索行后,MySQL server再进行过滤后返回(出自高性能MySQL,附录D EXPLAIN)。id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | film | NULL | ALL | null | null | null | NULL | 1000 | 11.11 | Using where |
REGEXP
explain select title from film where title REGEXP '^A';
复制代码
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | film | NULL | INDEX | null | idx_title | 767 | NULL | 1000 | 100 | Using where; Using index |
explain select * from film where title REGEXP '^A';
复制代码
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | film | NULL | ALL | null | null | null | NULL | 1000 | 100 | Using where |
Using where; Using index
与 Using index condition
Using where; Using index
:简单来说,咱们能够分开来看,Using where
就是MySQL Server在存储引擎检索行后,再过滤。Using index
就是覆盖索引查询,不须要回表获取行数据。加起来就是:使用覆盖索引检索行后,在MySQL Server进行过滤。Bonus:you may have something wrong in your query if the Extra value is not Using where and the table join type is ALL or index. 译文:若是type为ALL或index,可是Extra不是Using where时,查询语句或许有问题。测试
Using index Condition
:官方文档说这个与Index Condition Pushdown Optimization有关,官网简称为ICP
,在InnoDB
以及MyISAM
均可以使用,这里我截取InnoDB
关键信息。一、使用场景:the case where MySQL retrieves rows from a table using an index,索引检索行时使用
type为ref、range、index时使用,仅用于range、ref、eq_ref、ref_or_null 二、背景:Without ICP, the storage engine traverses the index to locate rows in the base table and returns them to the MySQL server which evaluates the WHERE condition for the rows,没有ICP,存储引擎遍历索引检索出行,返回到MySQL Server层进行WHERE条件过滤(眼熟有没有,using where)。 三、原理:With ICP enabled, and if parts of the WHERE condition can be evaluated by using only columns from the index, the MySQL server pushes this part of the WHERE condition down to the storage engine,若是WHERE条件或者其部分,仅使用索引中的列,MySQL server能够将这部分的WHERE子句交给存储引擎处理。(因为交给存储引擎,就是pushdown了 。。。) 四、做用:For InnoDB tables, ICP is used only for secondary indexes. The goal of ICP is to reduce the number of full-row reads and thereby reduce I/O operations. For InnoDB clustered indexes, the complete record is already read into the InnoDB buffer. Using ICP in this case does not reduce I/O,仅能够在二级索引使用,减小回表获取行数据次数,减小MySQL server与存储引擎之间的I/O操做,聚簇索引因为整条数据已经加载进InnoDB 缓冲区了,没有减小I/O操做。优化
一、ICP is used for the range, ref, eq_ref, and ref_or_null access methods when there is a need to access full table rows,仅用于range、ref、eq_ref、ref_or_null的type,且须要回表获取行数据的状况。 二、其余信息,请参考官网
一、explain select * from film where title LIKE 'A%'; range且须要回表 二、explain select title from film where title LIKE 'A%';不须要回表,没启动ICP 三、explain select title from film where title LIKE '%A'; index,无法用ICP
ICP
:SET optimizer_switch = 'index_condition_pushdown=off'; SET optimizer_switch = 'index_condition_pushdown=on';
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | film | NULL | range | idx_title | idx_title | 767 | NULL | 46 | 100.00 | Using where |
结论(在InnoDB
中):ICP
是一种MySQL
针对二级索引在range
、ref
、eq_ref
、ref_or_null
数据访问类型且不是覆盖索引(Using index)的一个优化机制,将MySQL server中进行的行数据过滤(二级索引可处理的)下推(push down)到存储引擎处理,减小回表读取行数据的次数,减小MySQL server与存储引擎之间的I/O操做。
本文从实例运行EXPLAIN
出发,简单介绍了ICP
,并对容易疏忽的LIKE
以及正则表达式的结果进行了介绍。
后续,会尽可能保持援引官网或者书里的资料,并结合实例分析,但愿对你们有所帮助,也欢迎纠错~