衡量一個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
以及正則表達式的結果進行了介紹。
後續,會盡可能保持援引官網或者書裏的資料,並結合實例分析,但願對你們有所幫助,也歡迎糾錯~