1. 程式人生 > 實用技巧 >mysql執行計劃,就這樣5000+字,被解釋的清清楚楚

mysql執行計劃,就這樣5000+字,被解釋的清清楚楚

上一次我們 通過實踐,解釋了mysql主從複製的原理和實踐,今天,我們來看一下mysql的執行計劃

在企業的應用場景中,為了知道優化SQL語句的執行,需要檢視SQL語句的具體執行過程,以加快SQL語句的執行效率。

可以使用explain+SQL語句來模擬優化器執行SQL查詢語句,從而知道mysql是如何處理sql語句的。

1、執行計劃中包含的資訊

ColumnMeaningidThe SELECT identifierselect_typeThe SELECT typetableThe table for the output rowpartitionsThe matching partitionstypeThe join typepossible_keysThe possible indexes to choosekeyThe index actually chosenkey_lenThe length of the chosen keyrefThe columns compared to the indexrowsEstimate of rows to be examinedfilteredPercentage of rows filtered by table conditionextraAdditional information

id

select查詢的序列號,包含一組數字,表示查詢中執行select子句或者操作表的順序

id號分為三種情況:

1、如果id相同,那麼執行順序從上到下

explainselect*fromemp ejoindept done.deptno= d.deptnojoinsalgrade sgone.salbetweensg.losalandsg.hisal;

2、如果id不同,如果是子查詢,id的序號會遞增,id值越大優先順序越高,越先被執行

explainselect*fromemp ewheree.deptnoin(selectd.deptnofromdept dwhered.dname='SALES');

3、id相同和不同的,同時存在:相同的可以認為是一組,從上往下順序執行,在所有組中,id值越大,優先順序越高,越先執行

explainselect*fromemp ejoindept done.deptno= d.deptnojoinsalgrade sgone.salbetweensg.losalandsg.hisalwheree.deptnoin(selectd.deptnofromdept dwhered.dname='SALES');

select_type

主要用來分辨查詢的型別,是普通查詢還是聯合查詢還是子查詢

select_type ValueMeaningSIMPLESimple SELECT (not using UNION or subqueries)PRIMARYOutermost SELECTUNIONSecond or later SELECT statement in a UNIONDEPENDENT UNIONSecond or later SELECT statement in a UNION, dependent on outer queryUNION RESULTResult of a UNION.SUBQUERYFirst SELECT in subqueryDEPENDENT SUBQUERYFirst SELECT in subquery, dependent on outer queryDERIVEDDerived tableUNCACHEABLE SUBQUERYA subquery for which the result cannot be cached and must be re-evaluated for each row of the outer queryUNCACHEABLE UNIONThe second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY)

--sample:簡單的查詢,不包含子查詢和union
explainselect*fromemp;
--primary:查詢中若包含任何複雜的子查詢,最外層查詢則被標記為Primaryexplainselectstaname,ename supnamefrom(selectename staname,mgrfromemp) tjoinempont.mgr=emp.empno;
--union:若第二個select出現在union之後,則被標記為union
explainselect*fromempwheredeptno =10unionselect*fromempwheresal >2000;
--dependent union:跟union類似,此處的depentent表示union或union all聯合而成的結果會受外部表影響explainselect*fromemp ewheree.empnoin(selectempnofromempwheredeptno =10unionselectempnofromempwheresal >2000)
--union result:從union表獲取結果的select
explainselect*fromempwheredeptno =10unionselect*fromempwheresal >2000;
--subquery:在select或者where列表中包含子查詢
explainselect*fromempwheresal > (selectavg(sal)fromemp) ;
--dependent subquery:subquery的子查詢要受到外部表查詢的影響explainselect*fromemp ewheree.deptnoin(selectdistinctdeptnofromdept);
--DERIVED: from子句中出現的子查詢,也叫做派生類,
explainselectstaname,ename supnamefrom(selectename staname,mgrfromemp) tjoinempont.mgr=emp.empno;
--UNCACHEABLE SUBQUERY:表示使用子查詢的結果不能被快取explainselect*fromempwhereempno = (selectempnofromempwheredeptno=@@sort_buffer_size);
--uncacheable union:表示union的查詢結果不能被快取:sql語句未驗證

table

對應行正在訪問哪一個表,表名或者別名,可能是臨時表或者union合併結果集 1、如果是具體的表名,則表明從實際的物理表中獲取資料,當然也可以是表的別名

2、表名是derivedN的形式,表示使用了id為N的查詢產生的衍生表

3、當有union result的時候,表名是union n1,n2等的形式,n1,n2表示參於union的id

type

type顯示的是訪問型別,訪問型別表示我是以何種方式去訪問我們的資料,最容易想的是全表掃描,直接暴力的遍歷一張表去尋找需要的資料,效率非常低下,訪問的型別有很多,效率從最好到最壞依次是:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

一般情況下,得保證查詢至少達到range級別,最好能達到ref

--all:全表掃描,一般情況下出現這樣的sql語句而且資料量比較大的話那麼就需要進行優化。
explainselect*fromemp;
--index:全索引掃描這個比all的效率要好,主要有兩種情況,一種是當前的查詢時覆蓋索引,即我們需要的資料在索引中就可以索取,或者是使用了索引進行排序,這樣就避免資料的重排序explain selectempnofromemp;
--range:表示利用索引查詢的時候限制了範圍,在指定範圍內進行查詢,這樣避免了index的全索引掃描,適用的操作符:=, <>, >, >=, <, <=, IS NULL, BETWEEN, LIKE, or IN()
explainselect*fromempwhereempnobetween7000and7500;
--index_subquery:利用索引來關聯子查詢,不再掃描全表explainselect*fromempwhereemp.jobin(selectjobfromt_job);
--unique_subquery:該連線型別類似與index_subquery,使用的是唯一索引explainselect*fromemp ewheree.deptnoin(selectdistinctdeptnofromdept);
--index_merge:在查詢過程中需要多個索引組合使用,沒有模擬出來--ref_or_null:對於某個欄位即需要關聯條件,也需要null值的情況下,查詢優化器會選擇這種訪問方式
explainselect*fromemp ewheree.mgrisnullore.mgr=7369;
--ref:使用了非唯一性索引進行資料的查詢
createindex idx_3onemp(deptno);
explainselect*fromemp e,dept dwheree.deptno=d.deptno;
--eq_ref :使用唯一性索引進行資料查詢explainselect*fromemp,emp2whereemp.empno= emp2.empno;
--const:這個表至多有一個匹配行,
explainselect*fromempwhereempno =7369;
--system:表只有一行記錄(等於系統表),這是const型別的特例,平時不會出現

possible_keys

顯示可能應用在這張表中的索引,一個或多個,查詢涉及到的欄位上若存在索引,則該索引將被列出,但不一定被查詢實際使用

explainselect*fromemp,deptwhereemp.deptno= dept.deptnoandemp.deptno=10;

key

實際使用的索引,如果為null,則沒有使用索引,查詢中若使用了覆蓋索引,則該索引和查詢的select欄位重疊。

explainselect*fromemp,deptwhereemp.deptno= dept.deptnoandemp.deptno=10;

key_len

表示索引中使用的位元組數,可以通過key_len計算查詢中使用的索引長度,在不損失精度的情況下長度越短越好。

explainselect*fromemp,deptwhereemp.deptno= dept.deptnoandemp.deptno=10;

ref

顯示索引的哪一列被使用了,如果可能的話,是一個常數

explainselect*fromemp,deptwhereemp.deptno= dept.deptnoandemp.deptno=10;

rows

根據表的統計資訊及索引使用情況,大致估算出找出所需記錄需要讀取的行數,此引數很重要,直接反應的sql找了多少資料,在完成目的的情況下越少越好

explainselect*fromemp;

extra

包含額外的資訊。

--using filesort:說明mysql無法利用索引進行排序,只能利用排序演算法進行排序,會消耗額外的位置
explainselect*fromemporderbysal;
--using temporary:建立臨時表來儲存中間結果,查詢完成之後把臨時表刪除
explainselectename,count(*)fromempwheredeptno =10groupbyename;
--using index:這個表示當前的查詢時覆蓋索引的,直接從索引中讀取資料,而不用訪問資料表。如果同時出現using where 表名索引被用來執行索引鍵值的查詢,如果沒有,表面索引被用來讀取資料,而不是真的查詢
explainselectdeptno,count(*)fromempgroupbydeptnolimit10;
--using where:使用where進行條件過濾
explainselect*fromt_userwhereid =1;
--using join buffer:使用連線快取,情況沒有模擬出來
--impossible where:where語句的結果總是false
explainselect*fromempwhereempno =7469;

感覺寫的不錯的,歡迎關注+轉發吧,您的鼓勵是我繼續的最大動力

相應的文章已經整理形成文件,git掃碼獲取資料看這裡

https://gitee.com/biwangsheng/personal.git