數據庫設計與優化 - MySQL執行計劃技術內幕詳解

背景mysql

一般咱們在經過SQL慢查詢日誌或其它三方工具分析出查詢性能較差的SQL語句後,常常須要定位緣由。那麼對於MYSQL咱們經常使用其內置的執行計劃(EXPLAIN)命令對慢的語句進行模擬執行查詢過程的分析,從而發現咱們語句的性能瓶頸點,再進行有針對性地優化工做。sql

執行計劃
緩存

1、爲何要分析執行計劃細節 ,咱們能獲得哪些方面信息 ?ide

  1. 理解語句執行的任務拆分和任務的執行順序;
    工具

  2. 分析執行計劃拆分的任務內部的劃分和含義;性能

  3. 分析單步執行任務的執行效果的理想程度;優化

  4. 瞭解語句的執行計劃建議可使用哪些索引;spa

  5. 查看執行計劃究竟內部用上了哪些目前的索引;3d

  6. 追蹤執行過程當中,對錶及字段的引用邏輯;日誌

  7. 瞭解每一個子任務過濾的表記錄數,從而調整表的鏈接和組織方式;

2、語法

EXPLAIN +SQL語句 , 如:EXPLAIN  select * from  table;

image.png

詳解分析結果

1、任務id理解

場景1. 執行任務id同樣,代表查詢優化器執行任務的順序是至上而下順序執行。

以下圖查詢語句,執行將從表t1開始,依次執行t3和t2的任務。

EXPLAIN  SELECT t2.* FROM t1,t2,t3 WHERE t1.id=t2.id AND t1.id=t3.id AND t1.other_column='';

image.png

場景2. 執行任務id不一樣, 查詢優化器執行規則爲:id值最大的任務優先被執行,按由大到小的順序依次執行拆分的任務項。

以下圖語句中執行過程:執行將從任務3開始,依次執行任務2和任務1;

EXPLAIN  SELECT t2.* FROM t2 WHERE id=(

    SELECT id FROM t1 WHERE id=(SELECT t3.id FROM t3 WHERE t3.other_column='')

);

image.png

場景3. 執行任務id相同與不一樣混合場景,查詢優化器優先執行任務id最大的;任務id同樣的部分單獨分組,至上而下順序執行。

以下圖語句中執行過程: 任務將被優先執行,而後再從上到下依次執行id=1d的兩個任務;

EXPLAIN

SELECT t2.* FROM( SELECT t3.idFROM t3 WHERE t3.other_column='' ) s1,t2 WHERE s1.id=t2.id ;

image.png

2、任務查詢類型 - select_type 

從語句總體上,劃分爲多種不一樣的查詢類型場景。

類型

描述

SIMPLE

簡單的select查詢,不包含子查詢和UNION

PRIMARY

查詢中若包含複雜的子部分,最外層查詢則被標記爲PRIMARY

SUBQUERY

SELECTWHERE列表中包含子查詢

DERIVED

FROM列表中包含的子查詢被標記爲DERVIED(衍生)MYSQL會遞歸執行這些子查詢,把結果放在臨時表裏面

UNION

若第二個SELECT出如今UNION以後,則被標記爲UNION;

UNION包含在FROM子句的子查詢中,外層SELECT被標記爲DERIVED

UNION RESULT

UNION表獲取結果的SELECT

1.SIMPLE類型,如:EXPLAIN  SELECT * FROM t_order;

image.png

2. PRIMARY和SUBQUERY類型

如:EXPLAIN  SELECT *,(SELECT   id   FROM   t_order_detail   WHERE  order_id=2) FROM   t_order  t1;

image.png

3. DERIVDE 衍生類型

如:EXPLAIN SELECT  t1.*  FROM t1,( SELECT t2.* FROM  t2 WHERE t2.id  =1) s2 WHERE t1.id=s2.id;

image.png

截圖中的<derivde2>中"2"表明從t2實體表,衍生出的虛擬表

4. UNION / UNION RESULT類型

如如下語句: EXPLAIN  SELECT  *  FROM  t1   UNION  SELECT  *  FROM  t2;

image.png

3、建議可使用哪些索引 - possible_keys

EXPLAIN

SELECT t1.orderno,t1.created_time,t2.goods_id,t2.id AS detailid

 FROM t_order t1 INNER JOIN t_order_detail t2 ON t1.id = t2.order_id 

WHERE t1.created_time >= '2020-07-18' AND t1.created_time <= '2020-07-20' ;

image.png

如上截圖待優化語句中,紅框中的索引,就是查詢優化器建議使用的索引進行對應的優化

4、實際使用到的索引 - key

以下圖中,就是查詢優化器實際用到的索引(多是多個)

CREATE INDEX  idx_col1_col2  ON t1 (col1, col2); 

EXPLAIN SELECT col1,col2 FROM t1 ;

image.png

5、分析是否充分用到了索引 - key_len

影響key_len值的因素:字符集設置、索引字段的長度(或字節數)、索引字段是否設置容許爲null。

字符集和 char / varchar類型字節對應關係

字符集

單箇中文佔字節空間

單個英文佔字空間

utf-8

3

1

gbk

2

1

場景1、對於char類型

單個字段key_len長度計算公式爲 = 字符集佔用最大字節空間 * 字段長度 + 是/否容許爲null (是=1, 否=0) ;

image.png

image.png

image.png

因此截圖1中的key_len=30的計算=3*10+0=30;

場景2、對於varchar類型

單個字段key_len長度計算公式爲 = 字符集佔用最大字節空間 * 字段長度+(預留長度) + 是/否容許爲null (是=1, 否=0) ;

公式中的預留長度值: mysql官網的介紹是: 長度在1 ~ 255之間,預留長度=1; 長度在256 ~ 16384之間,預留長度=2;

image.png

image.png

因此截圖2中的key_len=32的計算=3*10+2+0=32;

場景3、數字類型 (包括:int系列, 單精度、雙精度、Decimal等)

單個字段key_len長度計算公式爲 = 字段類型佔字節空間 + 是/否容許爲null (是=1, 否=0) ;

image.png

image.png

截圖3中的key_len=4的計算=4+0=4;

image.png

image.png

截圖4中的key_len=2的計算=1+1=2;

場景4、日期/日期時間/時間戳/時間等類型, 計算規則同場景三(這裏再也不贅述)。

其它須知原則

  1. 充分用到索引的key_len長度確定比未充分用到的要長,但字段加索引的原則是優先選擇長度較短的數據類型上加索引,查詢更高效;

  2. 複合索引key_len原則:複合索引有最左前綴的特性,若是複合索引能所有使用上,則是複合key_len爲各索引字段的key_len長度之和,這也能夠用來斷定複合索引是否部分使用,仍是所有使用;

 附數據類型佔字節空間對應表

數據類型

所佔空間

最大值

INT

4字節

10位長度.21億多

BIGINT

8字節

19位長

SMALLINT

2字節

-32768~32767

TINYINT

1字節

-128~127

FLOAT

4字節


DOUBLE

8字節


DECIMAL

4個字節存9個數字,小數點佔1個字節


CHAR


255個字符

VARCHAR

0~65535字節

16384個字符

TEXT


16K

MEDUIMTEXT


16M

LONGTEXT


4G

DATETIME

5.5及如下爲8字節;  5.6以上版本爲5字節

1000~9999(YEAR)

DATE

3字節

1000~9999(YEAR)

TIME

3字節


TIMESTAMP

4字節

1970~2038

6、任務訪問類型 - type

訪問類型值,從最好到最壞依次排序級別是:system  > const  > eq_ref  > ref  > fulltext > ref_or_null > index_merge  > unique_subquery  > index_subquery >  range  >  index >  ALL

級別值詳解

system:  優化器拆分的計劃id對應表中只有一條記錄

const:  經過索引一次就找到了目標數據

eq_ref:  惟一索引掃描,表中惟一記錄與之匹配,經常使用在主鍵或惟一索引

如執行包含主鍵id的索引查詢type即爲eq_ref級:EXPLAIN   SELECT  *  from  t1,t2  where  t1.id=t2.id 

ref:  非惟一索引掃描

如執行非惟一索引查詢type即爲ref級:  EXPLAIN   select  count(DISTINCTcol1)  from t1 where col1='ac'

image.png

range: 檢索給定範圍的行,使用一個索引來選擇行; (經常使用在bewteen and 、IN、<>); 

index : 計劃執行的是全表掃描( 經過索引掃描全表, select出的字段全是索引列) ;

ALL: 同上全表掃描,但掃描的是全表數據;

需掌握級別:system  > const  > eq_ref  > ref

                    range  >  index >  ALL

通常查詢須要保證達到range 級別,至少爲ref

7、對錶和列的引用 - ref

image.png

8、引用表多少行被優化器查詢到 - row

image.png

9、十分重要的額外信息 - extra

Extra

描述

Using filesort

說明mysql會對數據使用一個外部的索引(因爲不按索引排序規則排列查詢條件致使),而不是用表內索引順序進行讀取數據。這種沒法利用索引完成數據排序的狀況成爲文件排序

Using temporary

使用了臨時表保存中間結果,mysql對查詢結果排序時使用臨時表。常在ORDER   BY GROUP   BY中出現

Using index

是否使用了覆蓋索引

Using where

代表使用where進行了字段過濾

Using join buffer

代表使用了鏈接緩存

Impossible where

代表where子句的值老是false,   不能用來獲取任何元組

1. 產生filesort文件排序的緣由

建立複合索引時的字段排序順序是key(a,b,c); 可是採用where或order by 時,卻只按照c或其它字段排序,這樣查詢優化器就沒法採用索引來排序,需從新創建排序規則,即產生了這種狀況;

以下截圖所示:

image.png

image.png

image.png

解決辦法:order by c2,c3 ;

image.png

image.png

2. temporary表產生的緣由

在order by或group by排序 中不採用索引字段排序順序,致使產生中間臨時表。

image.png

image.png

解決辦法:group by c1,c2 ;

image.png

image.png

3.索引覆蓋舉例

image.png

image.png

4. join buffer理解:不循環數據逐一和另外一張表匹配,而是緩存整個小表數據,總體和另外一張表進行匹配方式,提高查詢效率;

5. impossible_where:  沒法查詢到任何數據

image.png

總結

以上就是MYSQL執行計劃模擬執行結果的全部細節分析。有任何關於這方面的問題,能夠在下方留言,你們一塊兒討論。下次咱們將給你們分享SQL高級查詢優化的諸多幹貨,請繼續關注!

相關文章
相關標籤/搜索