首先在Mysql的服務(wù)中有 連接器、查詢緩存(Mysql8 已經(jīng)刪除)、分析器、優(yōu)化器、執(zhí)行器等,所有跨存儲(chǔ)引擎的功能都在這一層實(shí)現(xiàn)
創(chuàng)新互聯(lián)建站是一家集網(wǎng)站建設(shè),宜城企業(yè)網(wǎng)站建設(shè),宜城品牌網(wǎng)站建設(shè),網(wǎng)站定制,宜城網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,宜城網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
而一條sql怎么執(zhí)行是由優(yōu)化器決定的,?優(yōu)化器是在表里面有多個(gè)索引的時(shí)候,決定使用哪個(gè)索引;或者在一個(gè)語句有多表關(guān)聯(lián)(join)的時(shí)候,決定各個(gè)表的連接順序。
而執(zhí)行計(jì)劃就是優(yōu)化器優(yōu)化后的sql的執(zhí)行的詳細(xì)方案
Mysql中查看執(zhí)行計(jì)劃的方式有兩種 : 1. 使用desc? ? 2.使用 explain? 使用它倆的效果是一樣的
接下來要通過執(zhí)行計(jì)劃知道sql是怎么執(zhí)行的
執(zhí)行計(jì)劃中有幾個(gè)重要的字段, 分別是?
id,? table,? type,? possible_keys,? key,? key_len, Extra
id :? 可以通過ID來查看在多表聯(lián)查中sql是先查詢哪張表的 id相同的從上往下依次執(zhí)行,id不同的id大的先執(zhí)行
table :? ?table當(dāng)然就是查詢的表名
type :? 查詢的類型? ?查詢類型分為??ALL,??index,??range,??ref ,?eq_ref,?const(system),??null
? ? ALL: 指的全盤掃描,沒有走任何索引? ?查詢結(jié)果集大于25% 優(yōu)化器可能會(huì)走全盤掃描? ?字符串查詢的時(shí)候一定要加"" 不然可能會(huì)全索引掃描(隱式轉(zhuǎn)換)? ?統(tǒng)計(jì)信息 失效 或者 過舊 也可能走全盤掃描? 因?yàn)閮?yōu)化器會(huì)參考統(tǒng)計(jì)信息來制定執(zhí)行計(jì)劃
???index:?全索引掃描? 就是掃描整顆索引樹
? ? ? ?range: 索引范圍? 查詢索引樹的一部分范圍? ?范圍索引中 ? ? =? =? like? 的效率會(huì)比? or? ?in? 的效率高, 使用like %再前面的不走索引
ref:? ?輔助索引的等值查詢? ??????????
? ? ? ? ? ? ? ? 當(dāng)查詢的數(shù)據(jù)量小,優(yōu)化器也有可能會(huì)走索引的全盤掃描? 這里我就不貼圖了;
???eq_ref : 多表連接查詢中,被連接的表的連接條件列是主鍵或者唯一鍵
???const(system): 主鍵 或者 唯一鍵 的等值查詢
? ? ? ? ? ?null: 沒有數(shù)據(jù)
他們的性能是依次遞增的 全盤掃描性能最差,? const性能最高
possible_keys:? 查詢過程中可能用到的索引
key: 真正使用到的索引
key_len:? 走索引的長(zhǎng)度
? ? 這個(gè)是怎么計(jì)算的呢???
???key_len 的計(jì)算方法 :
int 類型最長(zhǎng)存儲(chǔ)4個(gè)字節(jié)長(zhǎng)度的數(shù)字? 有not null? 是4字節(jié)? 沒有的話會(huì)花1字節(jié)存儲(chǔ)是不是null
tinyint 最大存儲(chǔ)一個(gè)字節(jié)? ? 也會(huì)花1字節(jié)來判斷是不是null
字符串類型 : 字符集 utf8mb4? 1-4字節(jié)
varchar超過255會(huì)預(yù)留2個(gè)字節(jié)存儲(chǔ)長(zhǎng)度 沒超預(yù)留1個(gè)字節(jié)
key_len 永遠(yuǎn)是你設(shè)置的長(zhǎng)度的最大的??
聯(lián)合索引可以通過key_len 來判斷走了幾個(gè)索引
? ? 使用desc format=json select * from table 可以查看詳細(xì)情況
filtered:? 索引掃描過濾掉數(shù)據(jù)的占比
Extra: 額外的信息?
??? Using filesort :MySQL?對(duì)數(shù)據(jù)在sql層進(jìn)行了排序,而不是按照表內(nèi)的索引進(jìn)行排序讀 取。 效率比較低
??? Using temporary :使用臨時(shí)表保存中間結(jié)果,也就是說 MySQL 在對(duì)查詢結(jié)果排序時(shí)使用了臨時(shí)表,常見于order by 或 group by。
??? Using index :表示 SQL 操作中使用了覆蓋索引(Covering Index),避免了訪問表的數(shù)據(jù)行,效率高。
??? Using index condition :表示 SQL 操作命中了索引,但不是所有的列數(shù)據(jù)都在索引樹上,還需要訪問實(shí)際的行記錄。
??? Using where :表示 SQL 操作使用了 where 過濾條件。
??? Select tables optimized away :基于索引優(yōu)化 MIN/MAX 操作或者 MyISAM 存儲(chǔ)引擎優(yōu)化 COUNT(*) 操作,不必等到執(zhí)行階段再進(jìn)行計(jì)算,查詢執(zhí)行計(jì)劃生成的階段即可完成優(yōu)化。
Using join buffer (Block Nested Loop) :表示 SQL 操作使用了關(guān)聯(lián)查詢或者子查詢,且需要進(jìn)行嵌套循環(huán)計(jì)算
mysql的查看執(zhí)行計(jì)劃的語句很簡(jiǎn)單,explain+你要執(zhí)行的sql語句就OK了。
舉一個(gè)例子
EXPLAIN SELECT * from employees where employees.gender='M'
返回的結(jié)果如下:
這些結(jié)果都代表什么?
id是一組數(shù)字,表示查詢中執(zhí)行select子句或操作表的順序。
如果id相同,則執(zhí)行順序從上至下。
如果是子查詢,id的序號(hào)會(huì)遞增,id越大則優(yōu)先級(jí)越高,越先會(huì)被執(zhí)行。
id如果相同,則可以認(rèn)為是一組,從上往下順序執(zhí)行,所有組中,id越高,優(yōu)先級(jí)越高,越容易執(zhí)行。
selecttype有simple,primary,subquery,derived(衍生),union,unionresult。
simple表示查詢中不包含子查詢或者union。
當(dāng)查詢中包含任何復(fù)雜的子部分,最外層的查詢被標(biāo)記成primary。
在select或where列表中包含了子查詢,則子查詢被標(biāo)記成subquery。
在from的列表中包含的子查詢被標(biāo)記成derived。
我們知道,當(dāng)一條sql查詢語句執(zhí)行時(shí),會(huì)通過服務(wù)層中的優(yōu)化器生成“查詢執(zhí)行計(jì)劃”。而使用explain關(guān)鍵字可以查詢到執(zhí)行的SQL查詢語句,從而知道MySQL是如何處理SQL的,即SQL的執(zhí)行計(jì)劃。因此根據(jù)執(zhí)行計(jì)劃我們可以選擇更好的索引和寫出更優(yōu)化的查詢語句,分析我們的查詢語句或是表結(jié)構(gòu)的性能瓶頸。
首先先解釋一下以上執(zhí)行計(jì)劃中各列的含義:
2. PRIMARY: 如果查詢語句中包含子查詢或者UNION操作,指最外層的SELECT;
3. UNION: UNION中的第二個(gè)或后面的SELECT語句;
4. UNION RESULT: UNION 的結(jié)果;
5. SUBQUERY: 子查詢中的第一個(gè)SELECT;
6. DERIVED: 導(dǎo)出表的SELECT(FROM子句的子查詢)。
下面介紹在實(shí)際開發(fā)過程中,常見的幾種類型:
1. const: 表示通過索引一次就找到數(shù)據(jù),用于比較primary key或者unique索引,很快就能找到對(duì)應(yīng)的數(shù)據(jù);
2. eq_ref: 唯一性索引掃描,對(duì)于每個(gè)索引鍵,表中只有一條記錄與之匹配,常用于主鍵或唯一索引掃描;
3. ref: 非唯一索引掃描,返回匹配的所有行;
4. index_merge: 經(jīng)常出現(xiàn)在使用一張表中的多個(gè)索引時(shí),mysql會(huì)將多個(gè)索引合并在一起;
5. range: 使用一個(gè)索引檢索指定范圍的行,一般在where語句中會(huì)出現(xiàn)between、、、in等范圍查詢;
6. index: index連接類型與ALL相同,只是遍歷索引樹;
7. ALL: 全表掃描,找到匹配行。與index比較,ALL需要掃描磁盤數(shù)據(jù),index值需要遍歷索引樹。
誤區(qū):
上述圖片可以看到,key_len的值為9(即hotelID(4)+dateTime(5)),沒有使用到全部聯(lián)合索引,以下是改良后的sql語句:
此時(shí)key_len的值為14(即hotelID(4)+dateTime(5)+dateTime(5)),使用到了key中所有索引。
優(yōu)化前:
很顯然,從explain執(zhí)行計(jì)劃中可以看到,該sql語句使用了兩個(gè)索引,但是從我們自己的優(yōu)化目標(biāo)中,只需要使用IDX_DataChange_CreateTime這一個(gè)索引就夠了,以下是我們通過一些小手段影響優(yōu)化器得到的優(yōu)化方案: