mysql執行計划中的extra列中表明了執行計划的每一步中的實現細節,其中包含了與索引相關的一些細節信息
其中跟索引有關的using index 在不同的情況下會出現Using index, Using where Using index ,Using index condition等
那么Using index 和 Using where;Using index 有什么區別?網上搜了一大把文章,說實在話也沒怎么弄懂,於是就自己動手試試。
本文僅從最簡單的單表去測試using index 和 using where using index以及簡單測試using index condition的情況的出現時機 。
執行計划的生成與表結構,表數據量,索引結構,統計信息等等上下文等多種環境有關,無法一概而論,復雜情況另論。
測試環境搭建
測試表以及測試數據搭建,類似於訂單表和訂單明細表,暫時先用訂單表做測試
測試表結構
create table test_order ( id int auto_increment primary key, user_id int, order_id int, order_status tinyint, create_date datetime ); create table test_orderdetail ( id int auto_increment primary key, order_id int, product_name varchar(100), cnt int, create_date datetime ); create index idx_userid_order_id_createdate on test_order(user_id,order_id,create_date); create index idx_orderid_productname on test_orderdetail(order_id,product_name);
測試數據(50W)
CREATE DEFINER=`root`@`%` PROCEDURE `test_insertdata`(IN `loopcount` INT) LANGUAGE SQL NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER COMMENT '' BEGIN declare v_uuid varchar(50); while loopcount>0 do set v_uuid = uuid(); insert into test_order (user_id,order_id,order_status,create_date) values (rand()*1000,id,rand()*10,DATE_ADD(NOW(), INTERVAL - RAND()*20000 HOUR)); insert into test_orderdetail(order_id,product_name,cnt,create_date) values (rand()*100000,v_uuid,rand()*10,DATE_ADD(NOW(), INTERVAL - RAND()*20000 HOUR)); set loopcount = loopcount -1; end while; END
Using index VS Using where Using index
首先,在"訂單表"上,這里是一個多列復合索引
create index idx_userid_order_id_createdate on test_order(user_id,order_id,create_date);
Using index
1,查詢的列被索引覆蓋,並且where篩選條件是索引的是前導列,Extra中為Using index
Using where Using index
1,查詢的列被索引覆蓋,並且where篩選條件是索引列之一但是不是索引的不是前導列,Extra中為Using where; Using index,
意味着無法直接通過索引查找來查詢到符合條件的數據
2,查詢的列被索引覆蓋,並且where篩選條件是索引列前導列的一個范圍,同樣意味着無法直接通過索引查找查詢到符合條件的數據
NULL(既沒有Using index,也沒有Using where Using index,也沒有using where)
1,查詢的列未被索引覆蓋,並且where篩選條件是索引的前導列,
意味着用到了索引,但是部分字段未被索引覆蓋,必須通過“回表”來實現,不是純粹地用到了索引,也不是完全沒用到索引,Extra中為NULL(沒有信息)
Using where
1,查詢的列未被索引覆蓋,where篩選條件非索引的前導列,Extra中為Using where
2,查詢的列未被索引覆蓋,where篩選條件非索引列,Extra中為Using where
using where 意味着通過索引或者表掃描的方式進程where條件的過濾,
反過來說,也就是沒有可用的索引查找,當然這里也要考慮索引掃描+回表與表掃描的代價。
這里的type都是all,說明MySQL認為全表掃描是一種比較低的代價。
Using index condition
1,查詢的列不全在索引中,where條件中是一個前導列的范圍
2,查詢列不完全被索引覆蓋,查詢條件完全可以使用到索引(進行索引查找)
參考:MySQL · 特性分析 · Index Condition Pushdown (ICP)
using index conditoin 意味着查詢列的某一部分無法直接使用索引
上述case1中,
如果禁用ICP(set optimizer_switch='index_condition_pushdown=off'),
執行計划是using where,意味着全表掃描,如果啟用ICP,執行計划為using index Condition,意味着在篩選的過程中實現過濾
上述case1中
第二個查詢條件無法直接使用索引,隱含了一個查找+篩選的過程。
兩個case的共同點就是無法直接使用索引。
結論:
1,Extra中的為Using index的情況
where篩選列是索引的前導列 &&查詢列被索引覆蓋 && where篩選條件是一個基於索引前導列的查詢,意味着通過索引超找就能直接找到符合條件的數據,並且無須回表
2,Extra中的為空的情況
查詢列存在未被索引覆蓋&&where篩選列是索引的前導列,意味着通過索引超找並且通過“回表”來找到未被索引覆蓋的字段,
3,Extra中的為Using where Using index:
出現Using where Using index意味着是通過索引掃描(或者表掃描)來實現sql語句執行的,即便是索引前導列的索引范圍查找也有一點范圍掃描的動作,不管是前非索引前導列引起的,還是非索引列查詢引起的。
尚未解決的問題:
查詢1
查詢2
查詢3(邏輯上等價於查詢1+查詢2),執行計划發生了很大的變化。
總結:
MySQL執行計划中的Extra中信息非常多,不僅僅包括Using index,Using where Using index,Using index condition,Using where,尤其是在多表連接的時候,這一點在相對MSSQL來說,不夠直觀或者結構化。
MSSQL中是通過區分索引查找(index seek),索引掃描(index scan),表掃描(table scan)來實現具體的查詢的,這圖形化的執行計划在不同的場景下是非常直觀的,要想完全弄懂MySQL的這個執行計划,可能要更多地在實踐中摸索。