前言
在MySQL中,我們知道加索引能提高查詢效率,這基本上算是常識了。但是有時候,我們加了索引還是覺得SQL查詢效率低下,我想看看有沒有使用到索引,掃描了多少行,表的載入順序等等,怎麼檢視呢?其實MySQL自帶的SQL分析神器Explain執行計劃就能完成以上的事情!
Explain有哪些資訊先確認一下試驗的MySQL版本,這裡使用的是5.7.31版本。
只需要在SQL語句前加上explain關鍵字就可以檢視執行計劃,執行計劃包括以下資訊:id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtered、Extra,總共12個欄位資訊。
然後建立三個表:
CREATE TABLE `tb_student` ( `id` int(10) NOT NULL AUTO_INCREMENT, `name` varchar(36) NOT NULL, PRIMARY KEY (`id`), KEY `index_name` (`name`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COMMENT='學生表';CREATE TABLE `tb_class` ( `id` INT(10) primary key not null auto_increment, `name` VARCHAR(36) NOT NULL, `stu_id` INT(10) NOT NULL, `tea_id` INT(10) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='班級表';CREATE TABLE `tb_teacher` ( `id` INT(10) primary key not null auto_increment, `name` VARCHAR(36) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='教師表';
Explain執行計劃詳解explain的使用很簡單,只需要在SQL語句前加上關鍵字explain即可,關鍵是怎麼看explain執行後返回的欄位資訊,這才是重點。
一、idSELECT識別符。這是SELECT的查詢序列號。SQL執行的順序的標識,SQL從大到小的執行。id列有以下幾個注意點:
id相同時,執行順序由上至下。id不同時,如果是子查詢,id的序號會遞增,id值越大優先順序越高,越先被執行。EXPLAIN SELECT * FROM `tb_student` WHERE id IN (SELECT stu_id FROM tb_class WHERE tea_id IN(SELECT id FROM tb_teacher WHERE `name` = '馬老師'));
根據原則,當id不同時,SQL從大到小執行,id相同則從上到下執行。
二、select_type表示select查詢的型別,用於區分各種複雜的查詢,例如普通查詢,聯合查詢,子查詢等等。
SIMPLE表示最簡單的查詢操作,也就是查詢SQL語句中沒有子查詢、union等操作。
PRIMARY當查詢語句中包含複雜查詢的子部分,表示複雜查詢中最外層的 select。
SUBQUERY當 select 或 where 中包含有子查詢,該子查詢被標記為SUBQUERY。
DERIVED在SQL語句中包含在from子句中的子查詢。
UNION表示在union中的第二個和隨後的select語句。
UNION RESULT代表從union的臨時表中讀取資料。
EXPLAIN SELECT u.`name` FROM ((SELECT s.id,s.`name` FROM `tb_student` s) UNION (SELECT t.id,t.`name` FROM tb_teacher t)) AS u;
<union2,3>代表是id為2和3的select查詢的結果進行union操作。
MATERIALIZEDMATERIALIZED表示物化子查詢,子查詢來自檢視。
三、table表示輸出結果集的表的表名,並不一定是真實存在的表,也有可能是別名,臨時表等等。
四、partitions表示SQL語句查詢時匹配到的分割槽資訊,對於非分割槽表值為NULL,當查詢的是分割槽表則會顯示分割槽表命中的分割槽情況。
五、type需要重點關注的一個欄位資訊,表示查詢使用了哪種型別,在 SQL最佳化中是一個非常重要的指標,依次從優到差分別是:system > const > eq_ref > ref > range > index > ALL。
system和const單表中最多有一條匹配行,查詢效率最高,所以這個匹配行的其他列的值可以被最佳化器在當前查詢中當作常量來處理。通常出現在根據主鍵或者唯一索引進行的查詢,system是const的特例,表裡只有一條元組匹配時(系統表)為system。
eq_refprimary key 或 unique key 索引的所有部分被連線使用 ,最多隻會返回一條符合條件的記錄,所以這種型別常出現在多表的join查詢。
ref相比eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分字首,可能會找到多個符合條件的行。
range使用索引選擇行,僅檢索給定範圍內的行。一般來說是針對一個有索引的欄位,給定範圍檢索資料,通常出現在where語句中使用 bettween...and、<、>、<=、in 等條件查詢 。
index掃描全表索引,通常比ALL要快一些。
ALL全表掃描,MySQL遍歷全表來找到匹配行,效能最差。
六、possible_keys表示在查詢中可能使用到的索引來查詢,而列出的索引並不一定是最終查詢資料所用到的索引。
七、key跟possible_keys有所區別,key表示查詢中實際使用到的索引,若沒有使用到索引則顯示為NULL。
八、key_len表示查詢用到的索引key的長度(位元組數)。如果單列索引,那麼就會把整個索引長度計算進去,如果是聯合索引,不是所有的列都用到,那麼就只計算實際用到的列,因此可以根據key_len來判斷聯合索引是否生效。
九、ref顯示了哪些列或常量被用於查詢索引列上的值。常見的值有:const,func,null,欄位名。
十、rowsmysql估算要找到我們所需的記錄,需要讀取的行數。可以透過這個資料很直觀的顯示 SQL 效能的好壞,一般情況下 rows 值越小越好。
十一、filtered指返回結果的行佔需要讀到的行(rows列的值)的百分比,一般來說越大越好。
十二、Extra表示額外的資訊。此欄位能夠給出讓我們深入理解執行計劃進一步的細節資訊。
Using index說明在select查詢中使用了覆蓋索引。覆蓋索引的好處是一條SQL透過索引就可以返回我們需要的資料。
Using where查詢時沒使用到索引,然後透過where條件過濾獲取到所需的資料。
Using temporary表示在查詢時,MySQL需要建立一個臨時表來儲存結果。臨時表一般會比較影響效能,應該儘量避免。
有時候使用DISTINCT去重時也會產生Using temporary。
Using filesort我們知道索引除了查詢中能起作用外,排序也是能起到作用的,所以當SQL中包含 ORDER BY 操作,而且無法利用索引完成排序操作的時候,MySQL不得不選擇相應的排序演算法來實現,這時就會出現Using filesort,應該儘量避免使用Using filesort。
總結一般最佳化SQL語句第一步是要知道這條SQL語句有哪些需要最佳化的,explain執行計劃就相當於一面鏡子,能把詳細的執行情況給開發者列出來。所以說善用explain執行計劃,能解決80%的SQL最佳化問題。
explain的資訊中,一般我們要關心的是type,看是什麼級別,如果是在網際網路公司一般需要在range以上的級別,接著關心的是Extra,有沒有出現filesort或者using template,一旦出現就要想辦法避免,接著再看key使用的是什麼索引,還有看filtered篩選比是多少。
我是一個努力讓大家記住的程式設計師。我們下期再見!!!
能力有限,如果有什麼錯誤或者不當之處,請大家批評指正,一起學習交流!