一、explain是什么?
簡單來講就是官方給的一個優化工具,直接在你的SQL語句前加上explain,執行整條語句,之后你就可以根據執行結果優化你的SQL啦,廢話不多說,直接剛實例
測試實例
1、創建測試表
-
CREATE TABLE `sql_explain_student` (
-
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
-
`name` varchar(30) DEFAULT NULL COMMENT '學生名字',
-
`age` int(11) DEFAULT NULL COMMENT '學生年齡',
-
`sex` tinyint(4) DEFAULT NULL COMMENT '性別',
-
`class` int(11) DEFAULT NULL COMMENT '學生班級',
-
PRIMARY KEY (`id`)
-
) ENGINE=InnoDB DEFAULT CHARSET=utf8
數據自己隨意建
2、來個簡單的測試語句
-
select * from sql_explain_student;
-
-
explain
-
select * from sql_explain_student;
結果:
之后我們就可以根據結果分析我們的語句的優劣,及如何優化了(先看看看這個表里的變量都是什么意思,,好吧~)
二、explain字段解釋及SQL好壞的判斷
table:顯示這一行的數據是關於哪張表的
type:這是重要的列,顯示連接使用了何種類型。從最好到最差的連接類型為const、eq_reg、ref、range、index和ALL
type顯示的是訪問類型,是較為重要的一個指標,結果值從好到壞依次是: system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL
一般來說,得保證查詢至少達到range級別,最好能達到ref。
possible_keys:顯示可能應用在這張表中的索引。如果為空,沒有可能的索引。可以為相關的域從WHERE語句中選擇一個合適的語句
key: 實際使用的索引。如果為NULL,則沒有使用索引。很少的情況下,MYSQL會選擇優化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX(indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MYSQL忽略索引
key_len:使用的索引的長度。在不損失精確性的情況下,長度越短越好
ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數
rows:MYSQL認為必須檢查的用來返回請求數據的行數
Extra:關於MYSQL如何解析查詢的額外信息。壞的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,結果是檢索會很慢
extra列返回的描述的意義
Distinct:一旦MYSQL找到了與行相聯合匹配的行,就不再搜索了
Not exists: MYSQL優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標准的行,就不再搜索了
Range checked for each Record(index map:#):沒有找到理想的索引,因此對於從前面表中來的每一個行組合,MYSQL檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連接之一
Using filesort: 看到這個的時候,查詢就需要優化了。MYSQL需要進行額外的步驟來發現如何對返回的行排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行
Using index: 列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對表的全部的請求列都是同一個索引的部分的時候
Using temporary 看到這個的時候,查詢需要優化了。這里,MYSQL需要創建一個臨時表來存儲結果,這通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上
Where used 使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。如果不想返回表中的全部行,並且連接類型ALL或index,這就會發生,或者是查詢有問題不同連接類型的解釋(按照效率高低的順序排序)
system 表只有一行:system表。這是const連接類型的特殊情況
const:表中的一個記錄的最大值能夠匹配這個查詢(索引可以是主鍵或惟一索引)。因為只有一行,這個值實際就是常數,因為MYSQL先讀這個值然后把它當做常數來對待
eq_ref:在連接中,MYSQL在查詢時,從前面的表中,對每一個記錄的聯合都從表中讀取一個記錄,它在查詢使用了索引為主鍵或惟一鍵的全部時使用
ref:這個連接類型只有在查詢使用了不是惟一或主鍵的鍵或者是這些類型的部分(比如,利用最左邊前綴)時發生。對於之前的表的每一個行聯合,全部記錄都將從表中讀出。這個類型嚴重依賴於根據索引匹配的記錄多少—越少越好
range:這個連接類型使用索引返回一個范圍中的行,比如使用>或<查找東西時發生的情況
index: 這個連接類型對前面的表中的每一個記錄聯合進行完全掃描(比ALL更好,因為索引一般小於表數據)
ALL:這個連接類型對於前面的每一個記錄聯合進行完全掃描,這一般比較糟糕,應該盡量避免
三、附錄:explain字段詳細解釋
id | SELECT識別符。這是SELECT的查詢序列號 |
---|---|
select_type | SELECT類型,可以為以下任何一種: SIMPLE:簡單SELECT(不使用UNION或子查詢) PRIMARY:最外面的SELECT UNION:UNION中的第二個或后面的SELECT語句 DEPENDENT UNION:UNION中的第二個或后面的SELECT語句,取決於外面的查詢 UNION RESULT:UNION 的結果SUBQUERY:子查詢中的第一個SELECT DEPENDENT SUBQUERY:子查詢中的第一個SELECT,取決於外面的查詢 DERIVED:導出表的SELECT(FROM子句的子查詢) |
table | 輸出的行所引用的表 |
type | 聯接類型。下面給出各種聯接類型,按照從最佳類型到最壞類型進行排序: system:表僅有一行(=系統表)。這是const聯接類型的一個特例。 const:表最多有一個匹配行,它將在查詢開始時被讀取。因為僅有一行,在這行的列值可被優化器剩余部分認為是常數。const表很快,因為它們只讀取一次! eqref:對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。 ref:對於每個來自於前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。 refornull:該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。indexmerge:該聯接類型表示使用了索引合並優化方法。 uniquesubquery:該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primarykey FROM singletable WHERE someexpr) uniquesubquery是一個索引查找函數,可以完全替換子查詢,效率更高。 indexsubquery:該聯接類型類似於uniquesubquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT keycolumn FROM singletable WHERE someexpr) range:只檢索給定范圍的行,使用一個索引來選擇行。 index:該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。 ALL:對於每個來自於先前的表的行組合,進行完整的表掃描。 |
possible_keys | 指出MySQL能使用哪個索引在該表中找到行 |
key | 顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。 |
key_len | 顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。 |
ref | 顯示使用哪個列或常數與key一起從表中選擇行。 |
rows | 顯示MySQL認為它執行查詢時必須檢查的行數。多行之間的數據相乘可以估算要處理的行數。 |
filtered | 顯示了通過條件過濾出的行數的百分比估計值。 |
Extra | 該列包含MySQL解決查詢的詳細信息 Distinct:MySQL發現第1個匹配行后,停止為當前的行組合搜索更多的行。 Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標准的行后,不再為前面的的行組合在該表內檢查更多的行。 range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。 Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。 Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。 Using temporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。 Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。 Using sortunion(...), Using union(...), Using intersect(...):這些函數說明如何為indexmerge聯接類型合並索引掃描。 Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查 詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。 |