MySQL 執行計划中Extra(Using where,Using index,Using index condition,Using index,Using where)的淺析


 

關於如何理解MySQL執行計划中Extra列的Using where、Using Index、Using index condition,Using index,Using where這四者的區別。首先,我們來看看官方文檔關於三者的簡單介紹(官方文檔並沒有介紹Using index,Using where這種情況):

 

 

Using index (JSON property: using_index)

 

The column information is retrieved from the table using only information in the index tree without having to do an additional seek to read the actual row. This strategy can be used when the query uses only columns that are part of a single index.

 

For InnoDB tables that have a user-defined clustered index, that index can be used even when Using index is absent from the Extra column. This is the case if type is index and key is PRIMARY.

 

從表中僅使用索引樹中的信息就能獲取查詢語句的列的信息, 而不必進行其他額外查找(seek)去讀取實際的行記錄。當查詢的列是單個索引的部分的列時, 可以使用此策略。(簡單的翻譯就是:使用索引來直接獲取列的數據,而不需回表)。對於具有用戶定義的聚集索引的 InnoDB 表, 即使從Extra列中沒有使用索引, 也可以使用該索引。如果type是index並且Key是主鍵, 則會出現這種情況。

 

 

 

Using where (JSON property: attached_condition)

 

 

A WHERE clause is used to restrict which rows to match against the next table or send to the client. Unless you specifically intend to fetch or examine all rows from the table, 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.

 

Using where has no direct counterpart in JSON-formatted output; the attached_condition property contains any WHERE condition used.

 

where 子句用於限制與下一個表匹配的行記錄或發送到客戶端的行記錄。除非您特意打算從表中提取或檢查所有行,否則如果Extra值不是Using where並且表連接類型為ALL或index,則查詢可能會出錯。

 

 

Using index condition (JSON property: using_index_condition)

 

Tables are read by accessing index tuples and testing them first to determine whether to read full table rows. In this way, index information is used to defer (“push down”) reading full table rows unless it is necessary. See Section 8.2.1.5, “Index Condition Pushdown Optimization”.

 

 

 

 

在展開講述這些之前,我們先來回顧一下執行計划中的Type與Extra部分內容。因為下面很多部分都需要這方面的知識點(其實最上面有些有關Extra的描述看起來很生澀,感覺不是那么通熟易懂!)

 

 

Type的相關知識點:

 

 

clip_image001

 

 

由左至右,性能由最差到最好

 

ALL:Full Table Scan, MySQL將遍歷全表以找到匹配的行

 

index:Full Index Scan,index與ALL區別為index類型只遍歷索引樹

 

range:索引范圍掃描,對索引的掃描開始於某一點,返回匹配值域的行,常見於between、<、>等的查詢

 

ref:非唯一性索引掃描,返回匹配某個單獨值的所有行。常見於使用非唯一索引即唯一索引的非唯一前綴進行的查找

 

eq_ref:唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配。常見於主鍵或唯一索引掃描

 

const、system:當MySQL對查詢某部分進行優化,並轉換為一個常量時,使用這些類型訪問。如將主鍵置於where列表中,MySQL就能將該查詢轉換為一個常量

 

NULL:MySQL在優化過程中分解語句,執行時甚至不用訪問表或索引

 

 

 

Extra的相關知識點:

 

 

Using temporary

 

    表示MySQL需要使用臨時表來存儲結果集,常見於排序和分組查詢

 

Using filesort

 

    MySQL中無法利用索引完成的排序操作稱為文件排序

 

Using Index

 

    表示直接訪問索引就能夠獲取到所需要的數據(覆蓋索引,不需要通過索引回表;

 

   覆蓋索引: 如果一個索引包含(或者說覆蓋)所有需要查詢的字段的值。我們稱之為覆蓋索引。如果索引的葉子節點中已經包含要查詢的數據,那么還有什么必要再回表查詢呢?

 

Using Index Condition

   

     在MySQL 5.6版本后加入的新特性(Index Condition Pushdown);會先條件過濾索引,過濾完索引后找到所有符合索引條件的數據行,隨后用 WHERE 子句中的其他條件去過濾這些數據行;

 

Using where

 

    表示MySQL服務器在存儲引擎收到記錄后進行后過濾(Post-filter),如果查詢未能使用索引,Using where的作用只是提醒我們MySQL將用where子句來過濾結果集。這個一般發生在MySQL服務器,而不是存儲引擎層。一般發生在不能走索引掃描的情況下或者走索引掃描,但是有些查詢條件不在索引當中的情況下。

 

 

 

下面我們通過實驗來測試、驗證一下,並加深一下我們對這些概念的理解,測試環境數據庫為Sakila, 首先使用下面腳本准備測試環境:

 

CREATE TABLE TEST(
  i1 INT NOT NULL DEFAULT 0,
  i2 INT NOT NULL DEFAULT 0,
  d DATE DEFAULT NULL,
  f INT  default 0,
  PRIMARY KEY (i1, i2)
) ENGINE = InnoDB;
 
INSERT INTO TEST VALUES
(1, 1, '1998-01-01',1), (1, 2, '1999-01-01',2),
(1, 3, '2000-01-01',1), (1, 4, '2001-01-01',2),
(1, 5, '2002-01-01',1), (2, 1, '1998-01-01',2),
(2, 2, '1999-01-01',1), (2, 3, '2000-01-01',2),
(2, 4, '2001-01-01',1), (2, 5, '2002-01-01',2),
(3, 1, '1998-01-01',1), (3, 2, '1999-01-01',2),
(3, 3, '2000-01-01',1), (3, 4, '2001-01-01',2),
(3, 5, '2002-01-01',1), (4, 1, '1998-01-01',2),
(4, 2, '1999-01-01',1), (4, 3, '2000-01-01',2),
(4, 4, '2001-01-01',1), (4, 5, '2002-01-01',2),
(5, 1, '1998-01-01',1), (5, 2, '1999-01-01',2),
(5, 3, '2000-01-01',1), (5, 4, '2001-01-01',2),
(5, 5, '2002-01-01',1); 

 

 

 

 

 

Extra中為Using where的情況

 

 

Extra中出現Using where,通常來說,意味着全表掃描或者在查找使用索引的情況下,但是還有查詢條件不在索引字段當中。具體來說有很多種情況,下面簡單羅列一下測試過程中遇到的各種情況(部分案例)。

 

 

1: 查詢條件中的相關列,不是索引字段, 全表掃描后,通過Using where過濾獲取所需的數據。

 

 

通俗來說,因為字段D沒有索引,所以必須全表掃描,然后在服務器層使用WHERE過濾數據。

 

 

mysql> EXPLAIN
    -> SELECT COUNT(*) FROM TEST WHERE D = '2000-01-01';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | TEST  | ALL  | NULL          | NULL | NULL    | NULL |   25 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

 

 

 

2 (type=ref)非唯一性索引掃描,但是由於索引未覆蓋所有查詢條件(字段d並未包含在聚集索引PRIMARY),在存儲引擎返回記錄后,仍然需要過濾數據(排除d != '2000-01-01'的數據)。

 

 

mysql> EXPLAIN
    -> SELECT COUNT(*) FROM TEST WHERE i1 = 3 AND d = '2000-01-01';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | TEST  | ref  | PRIMARY       | PRIMARY | 4       | const |    5 | Using where |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)
 
mysql> 
mysql> EXPLAIN
    -> SELECT * FROM TEST WHERE i1 = 3 AND d = '2000-01-01';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | TEST  | ref  | PRIMARY       | PRIMARY | 4       | const |    5 | Using where |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)
 
mysql>
mysql> EXPLAIN
    -> SELECT COUNT(i1) FROM TEST WHERE i1 = 3 AND d = '2000-01-01';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | TEST  | ref  | PRIMARY       | PRIMARY | 4       | const |    5 | Using where |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)
 
mysql>

 

 

 

這里即使在存儲引擎層進行非唯一性索引掃描,但是索引掃描過程中,只是過濾獲取i1=3的行記錄,相關記錄返回MySQL服務器后,還需要對記錄進行過濾,只返回d = '2000-01-01'的記錄。簡單來說,索引無法過濾掉無效的行。如下所示i1=3的記錄有5條,但是i1 = 3 AND d = '2000-01-01'的記錄只有一條。如下所示:

 

 

 

mysql> SELECT * FROM TEST WHERE i1 = 3 ;
+----+----+------------+------+
| i1 | i2 | d          | f    |
+----+----+------------+------+
|  3 |  1 | 1998-01-01 |    1 |
|  3 |  2 | 1999-01-01 |    2 |
|  3 |  3 | 2000-01-01 |    1 |
|  3 |  4 | 2001-01-01 |    2 |
|  3 |  5 | 2002-01-01 |    1 |
+----+----+------------+------+
5 rows in set (0.00 sec)
 
mysql> SELECT * FROM TEST WHERE i1 = 3 AND d = '2000-01-01';
+----+----+------------+------+
| i1 | i2 | d          | f    |
+----+----+------------+------+
|  3 |  3 | 2000-01-01 |    1 |
+----+----+------------+------+
1 row in set (0.00 sec)
 
mysql> 

 

 

 

 

3:WHERE篩選條件不是索引的前導列,導致不走索引,而走全表掃描。

 

 

 

其實此處是因為WHERE中的刷選條件不是索引的前導列,所以執行計划走全表掃描(ALL),然后在服務器層進行過濾數據。

 

 

mysql> EXPLAIN
    -> SELECT COUNT(i1) FROM TEST WHERE i2=4 AND d = '2000-01-01';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | TEST  | ALL  | NULL          | NULL | NULL    | NULL |   25 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
 
mysql> 

 

 

 

注意:

 

Using where過濾元組和執行計划是否走全表掃描或走索引查找沒有關系。如上測試所示,Using where: 僅僅表示MySQL服務器在收到存儲引擎返回的記錄后進行后過濾(Post-filter)。 不管SQL語句的執行計划是全表掃描(type=ALL)或非唯一性索引掃描(type=ref)。網上有種說法Using where:表示優化器需要通過索引回表查詢數據" ,上面實驗可以證實這種說法完全不正確。

 

 

 

Extra中為Using index的情況

 

 

表示直接訪問索引就能夠獲取到所需要的數據(索引覆蓋,不需要通過索引回表。

 

注意:執行計划中的Extra列的Using index跟type列的index不要混淆。Extra列的Using index表示索引覆蓋。而type列的index表示Full Index Scan。

 

 

 首先,我們在表TEST上創建二級索引IX_TEST_N1

 

mysql> CREATE INDEX IX_TEST_N1 ON TEST(d);
Query OK, 0 rows affected (0.10 sec)
Records: 0  Duplicates: 0  Warnings: 0
 
 
mysql> EXPLAIN
    -> SELECT COUNT(*) FROM TEST WHERE D = '2000-01-01';
+----+-------------+-------+------+---------------+------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key        | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+------------+---------+-------+------+-------------+
|  1 | SIMPLE      | TEST  | ref  | IX_TEST_N1    | IX_TEST_N1 | 4       | const |    5 | Using index |
+----+-------------+-------+------+---------------+------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
 
mysql> EXPLAIN
    -> SELECT * FROM TEST WHERE D = '2000-01-01';
+----+-------------+-------+------+---------------+------------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key        | key_len | ref   | rows | Extra |
+----+-------------+-------+------+---------------+------------+---------+-------+------+-------+
|  1 | SIMPLE      | TEST  | ref  | IX_TEST_N1    | IX_TEST_N1 | 4       | const |    5 | NULL  |
+----+-------------+-------+------+---------------+------------+---------+-------+------+-------+
1 row in set (0.00 sec)
 
mysql> 

 

 

 

 

 

如上所示,上面SQL例子中,Extra為 Using index的表示覆蓋索引,而不需回表。而Null則表示需要回表。

 

mysql> EXPLAIN
    -> SELECT i1, i2 FROM TEST WHERE i1=3 AND i2=5;
+----+-------------+-------+-------+---------------+---------+---------+-------------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref         | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+-------------+------+-------------+
|  1 | SIMPLE      | TEST  | const | PRIMARY       | PRIMARY | 8       | const,const |    1 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+-------------+------+-------------+
1 row in set (0.00 sec)
 
mysql> EXPLAIN
    -> SELECT * FROM TEST WHERE i1=3 AND i2=5;
+----+-------------+-------+-------+---------------+---------+---------+-------------+------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref         | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------------+------+-------+
|  1 | SIMPLE      | TEST  | const | PRIMARY       | PRIMARY | 8       | const,const |    1 | NULL  |
+----+-------------+-------+-------+---------------+---------+---------+-------------+------+-------+
1 row in set (0.00 sec)
 
mysql>

 

 

 

Extra中為Using where; Using index的情況

 

 

 

下面我們關閉Index Extensions選項(具體可以參考博客MySQL索引擴展(Index Extensions)學習總結),那么二級索引(Secondary Index)就不會自動補齊主鍵,將主鍵列追加到二級索引列后面,此時,Extra則會由Using index變為Using where; Using index。如下所示

 

 

mysql> EXPLAIN
    -> SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01';
+----+-------------+-------+------+---------------+------+---------+-------------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref         | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+-------------+------+-------------+
|  1 | SIMPLE      | t1    | ref  | PRIMARY,k_d   | k_d  | 8       | const,const |    1 | Using index |
+----+-------------+-------+------+---------------+------+---------+-------------+------+-------------+
1 row in set (0.00 sec)
 
mysql> SET optimizer_switch = 'use_index_extensions=off';
Query OK, 0 rows affected (0.00 sec)
 
mysql> EXPLAIN
    -> SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01';
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra                    |
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | t1    | ref  | PRIMARY,k_d   | k_d  | 4       | const |    5 | Using where; Using index |
+----+-------------+-------+------+---------------+------+---------+-------+------+--------------------------+
1 row in set (0.00 sec)
 
mysql> 

 

clip_image002

 

 

這樣的細微差別,代表什么區別呢? 我們可以理解為:MySQL服務器在收到存儲引擎返回i1 = 3的記錄后進行后過濾(Post-filter),過濾返回d = '2000-01-01'的記錄。另外,我們以樣例數據庫sakila為例, 如下所示,表rental在字段customer_id上建有二級索引idx_fk_customer_id ,下面兩個SQL語句的執行計划就是Using index 與Using where; Using index的區別。

 

 

mysql> EXPLAIN SELECT customer_id FROM rental WHERE customer_id=300;
+----+-------------+--------+------+--------------------+--------------------+---------+-------+------+-------------+
| id | select_type | table  | type | possible_keys      | key                | key_len | ref   | rows | Extra       |
+----+-------------+--------+------+--------------------+--------------------+---------+-------+------+-------------+
|  1 | SIMPLE      | rental | ref  | idx_fk_customer_id | idx_fk_customer_id | 2       | const |   31 | Using index |
+----+-------------+--------+------+--------------------+--------------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
 
mysql>
 
 
 
mysql> EXPLAIN SELECT customer_id FROM rental WHERE customer_id>=300;
+----+-------------+--------+-------+--------------------+--------------------+---------+------+------+--------------------------+
| id | select_type | table  | type  | possible_keys      | key                | key_len | ref  | rows | Extra                    |
+----+-------------+--------+-------+--------------------+--------------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | rental | range | idx_fk_customer_id | idx_fk_customer_id | 2       | NULL | 7910 | Using where; Using index |
+----+-------------+--------+-------+--------------------+--------------------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
 
mysql> 

 

clip_image003

 

 

上面兩個SQL語句都能滿足覆蓋索引的條件,但是為什么第二個SQL的執行計划是Using where; Using index呢? 相當長的一段時間里,即使查閱了大量關於Using where; Using indexUsing index的區別的資料,但是都是霧里看花,越糾結就越糊塗。非常讓人抓狂,而且始終沒有弄清楚到底是啥區別:

 

在《高性能MySQL》的相關章節,書本里面有這樣的解釋:MySQL服務器在存儲引擎返回行以后在應用WHERE條件過濾。

 

摘抄一段在此,方便各位理解:

 

InnoDB只有在訪問行的時候才會對其加鎖,而索引能夠減少InnoDB訪問的行數,從而減少鎖的數量。但這只有當InnoDB在存儲引擎層能夠過濾

掉所有不需要的行時才有效,如果索引無法過濾掉無效的行,那么在InnoDB檢索到數據並返回給服務器層以后, MySQL服務器才能應用WHERE子句。

這時已經無法避免鎖定行了:InnoDB已經鎖定了這些行,到適當的時候才釋放。在MySQL 5.1和之后的版本中, InnoDB可以在服務器端過濾掉行后

就釋放鎖,但是在早期的MySQL版本中,InnoDB只有在事務提交后才能釋放鎖。

 

是否有人看完上面這段解釋,還是有點迷惑。WHERE條件customer_id>=300 ,執行計划使索引范圍掃描,對索引的掃描customer_id大於等於300的行,返回了所有匹配的值,這個已經是經過過濾后的數據了,不應該在服務器使用WHERE過濾數據啊? Why??? 直到后面看了何登成大神SQL中的where條件,在數據庫中提取與應用淺析這篇文章,才基本上明白,MySQL對WHERE條件的分解和提取。簡單點理解,就是Using where; Using index 這個表示在索引的掃描過程中,也是需要過濾數據的(Index First Key 、Index Last Key),其實表掃描和索引掃描也是很類似的。只是發生的層面不一樣。個人覺得這樣的解釋已經是合理的,如有不對,敬請指教。

 

還有一個細節,就是你們會發現出現Using where; Using index意味着返回的記錄是超過一條, 而Using index意味着返回單條記錄,而且Type也是有所區別,從ref"或eq_ref 到 range。(這個只是簡單推測,沒有經過嚴格驗證)

 

注意:不要把Extra列的"Using index"與type列的"index"搞混淆,其實這兩者完全不同,type列和覆蓋索引毫無關系,它只是表示這個查詢訪問數據的方式,或者說MySQL查找行的方式。

 

 

 

 

 

Extra中為Using index condition的情況

 

 

Extra為Using Index Condition 表示會先條件過濾索引,過濾完索引后找到所有符合索引條件的數據行,隨后用 WHERE 子句中的其他條件去過濾這些數據行。Index Condition Pushdown (ICP)是MySQL 5.6 以上版本中的新特性,是一種在存儲引擎層使用索引過濾數據的一種優化方式。ICP開啟時的執行計划含有 Using index condition 標示 ,表示優化器使用了ICP對數據訪問進行優化。

 

關於ICP的相關資料,摘抄其它博客的兩段介紹:

 

 

a 當關閉ICP時,Index僅僅是data access的一種訪問方式,存儲引擎通過索引回表獲取的數據會傳遞到MySQL Server 層進行WHERE條件過濾。

 

b 當打開ICP時,如果部分WHERE條件能使用索引中的字段,MySQL Server 會把這部分下推到引擎層,可以利用Index過濾的WHERE條件在存儲引擎層進行數據過濾,而非將所有通過Index Access的結果傳遞到MySQL Server層進行WHERE過濾.

 

優化效果:ICP能減少引擎層訪問基表的次數和MySQL Server 訪問存儲引擎的次數,減少io次數,提高查詢語句性能

 

ICP(index condition pushdown)是MySQL利用索引(二級索引)元組和篩字段在索引中的WHERE條件從表中提取數據記錄的一種優化操作。ICP的思想是:存儲引擎在訪問索引的時候檢查篩選字段在索引中的WHERE條件(pushed index condition,推送的索引條件),如果索引元組中的數據不滿足推送的索引條件,那么就過濾掉該條數據記錄。ICP(優化器)盡可能的把index condition的處理從Server層下推到Storage Engine層。Storage Engine使用索引過過濾不相關的數據,僅返回符合Index Condition條件的數據給Server層。也是說數據過濾盡可能在Storage Engine層進行,而不是返回所有數據給Server層,然后后再根據WHERE條件進行過濾。sh

 

 

下面是博客Index Condition Pushdown中的兩幅插圖,形象的描述了使用ICP和不使用ICP,優化器的數據訪問和提取的過程。

 

 

 

 

clip_image004

 

 

 

 

clip_image005

 

下面我們來看看案例吧,在sakila數據庫的表rental上,在字段`rental_date`,`inventory_id`,`customer_id`上建有唯一索引rental_date,那么在開啟ICP時,

Extra會出現Using index condition

 

 

 
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.6.41    |
+-----------+
1 row in set (0.00 sec)
 
mysql> set optimizer_switch='index_condition_pushdown=on';
Query OK, 0 rows affected (0.00 sec)
 
mysql> explain 
    -> select * from rental 
    -> where rental_date = '2006-02-14 15:16:03' 
    ->   and customer_id >= 300 
    ->   and customer_id <= 400;
+--+-----------+------+-----+-------------------+-----------+--------+-------+------+----------------------+
|id|select_type|table| type | possible_keys     | key       |key_len |ref    | rows | Extra                |
+--+-----------+------+-----+-------------------+-----------+--------+-------+------+----------------------+
|1 |SIMPLE     |rental| ref |rental_date,idx_… |rental_date| 5      | const |  181 | Using index condition 
+--+-----------+------+-----+-------------------------------+--------+-------+-------+------+--------------+
1 row in set (0.00 sec)
 
mysql> set optimizer_switch='index_condition_pushdown=off';
Query OK, 0 rows affected (0.00 sec)
 
mysql> explain 
    -> select * from rental 
    -> where rental_date = '2006-02-14 15:16:03' 
    ->   and customer_id >= 300 
    ->   and customer_id <= 400;
+----+-------------+--------+------+--------------------------------+-------------+---------+-------+------+-------------+
| id | select_type | table  | type | possible_keys                  | key         | key_len | ref   | rows | Extra       |
+----+-------------+--------+------+--------------------------------+-------------+---------+-------+------+-------------+
|  1 | SIMPLE      | rental | ref  | rental_date,idx_fk_customer_id | rental_date | 5       | const |  181 | Using where |
+----+-------------+--------+------+--------------------------------+-------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
 
mysql> 

 

 

 

ICP的一些使用限制:

 

1. SQL需要全表訪問時,ICP的優化策略可用於range, ref, eq_ref, ref_or_null類型的訪問數據方法 。

2. 支持InnoDBMyISAM表。

3. ICP只能用於二級索引,不能用於主索引。

4. 並非全部WHERE條件都可以用ICP篩選,如果WHERE條件的字段不在索引列中,還是要讀取整表的記錄到Server端做WHERE過濾。

5. ICP的加速效果取決於在存儲引擎內通過ICP篩選掉的數據的比例。

6. MySQL 5.6版本的不支持分表的ICP功能,5.7版本的開始支持。

7. SQL使用覆蓋索引時,不支持ICP優化方法。

 

 

 

參考資料:

 

 

http://hedengcheng.com/?p=577

https://mariadb.com/kb/en/library/index-condition-pushdown/

http://www.cnblogs.com/gomysql/p/3657395.html

https://wenku.baidu.com/view/dab46f72f46527d3240ce065.html

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM