使用 explain 優化你的 mysql 性能

本文是關於在學習《高性能 Mysql》附錄 D 中關於 Explain 如何獲取執行計劃信息相關總結。MySQL 提供了一個 EXPLAIN 命令,它能夠對 SELECT 語句進行分析,獲取優化器對當前查詢的執行計劃,以供開發人員針對相關 SQL 進行優化。在 SELECT 語句前加上 Explain 就能夠查看到相關信息, 例如:mysql

EXPLAIN SELECT * from user_info WHERE id < 300;

複製代碼

Explain 特色

  • explain 返回的結果是以表爲粒度的,每一個表輸出一行,這裏的表示廣義上的表,能夠是一個子查詢,也能夠是一個 UNION 後的結果。
  • 並非全部的 explain 都不執行查詢,若是 FROM 子句裏包含了子查詢,那麼 MySql 實際上會執行子查詢之外層對於外層查詢的優化。
  • explain 沒法告訴咱們觸發器,存儲過程以及 UDF 是如何影響查詢的
  • explain 對於內存排序和臨時文件排序都使用 「filesort」
  • explain 對於磁盤上的臨時表和內存上的臨時表都使用 「Using temporary」
  • explain 只能解析 Select 查詢,對於 update,insert 等都不支持,咱們可使用 select 來模擬 update 操做近似獲取 update 的執行過程

Explain 中的列

id

SELECT 查詢的標識符. 每一個 SELECT 都會自動分配一個惟一的標識符.sql

select_type

select_type 表示了查詢的類型, 它的經常使用取值有:segmentfault

  • SIMPLE:表示此查詢不包含 UNION 查詢或子查詢
  • SUBQUERY:包含在 Select 列表中的子查詢,也就是不在 FROM 子句中的子查詢
  • DERIVED:表示包含在 From 子句中的 Select 查詢
  • UNION:表示此查詢是 UNION 的第二和隨後的查詢
  • UNION RESULT: 從 UNION 匿名臨時表檢索結果的 SELECT
  • PRIMARY, 表示此查詢是最外層的查詢
  • DEPENDENT UNION: UNION 中的第二個或後面的查詢語句, DEPENDENT 意味着 Select 依賴於外層查詢中發現的數據
  • DEPENDENT SUBQUERY: 包含在 Select 列表中的子查詢, 但子查詢依賴於外層查詢的結果.
table

查詢的是哪一個表,mysql 查詢優化器執行的關聯順序並不和咱們寫 SQL 時關聯的順序一致,下面咱們講一下 Mysql 是如何對關聯查詢做優化的:性能優化

  • Mysql 查詢執行計劃老是按照左側深度優先樹的規則去執行,也就是從一個表開始一直嵌套循環,並不會相似平衡二叉樹同樣兩個分支同時執行
  • 在多表關聯時,能夠經過多種不一樣的關聯順序獲取相同的執行結果,查詢優化器會評估不一樣的順序選擇一個代價最小的關聯查詢
  • 若是你不想要優化器改變你的關聯順序,可使用 STRAIGHT JOIN 關鍵字強制使用你的關聯順序去執行
  • 若是關聯表特別多時,超過 optimizer_search_depth 的限制時,優化器評估每一種關聯順序的執行成本過高,這時會選擇「貪婪」的搜索模式
type

type 字段比較重要, 它提供了判斷查詢是否高效的重要依據依據. 經過 type 字段, 咱們判斷這次查詢是全表掃描仍是索引掃描等,type 類型的性能比較,一般來講, 不一樣的 type 類型的性能關係以下:bash

ALL < index < range < ref < eq_ref < const < system < NULL服務器

  • NULL:這種訪問意味着 Mysql 能在優化階段分解查詢語句,在執行階段不須要訪問表或者索引
  • system: 預先知道整個表中只有一條數據. 這個類型是特殊的 const 類型
# 由於表中backend_user是主鍵,因此子查詢裏最多能夠選出一條數據,因此最外層查詢的type是system,裏層查詢的type是const
explain select * from (select * from backend_user where id = 1) a;
複製代碼
  • const:針對主鍵或惟一索引的等值查詢掃描, 最多隻返回一行數據. const 查詢速度很是快, 由於它僅僅讀取一次便可
  • eq_ref: 此類型一般出如今多表的 join 查詢, 表示對於前表的每個結果, 都只能匹配到後表的一行結果. 而且查詢的比較操做一般是 =, 查詢效率較高.
  • ref:此類型一般出如今多表的 join 查詢, 針對於非惟一或非主鍵索引, 或者是使用了最左前綴規則索引的查詢,可能會查詢出多個值
  • range: 表示使用索引範圍查詢, 經過索引字段範圍獲取表中部分數據記錄. 這個類型一般出如今 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操做中。可是對於一樣的 type = range 的查詢,性能上仍是有區別的:
# 雖然是都是範圍查詢,其實第二個查詢時多個等值條件查詢
# 對於第一個查詢,mysql 沒法再使用該列後面的其它查詢索引了,而第二個則能夠繼續使用索引
select id from actor where id > 45 and class_id = 3;
select id from actor where id in (44, 47, 48) and class_id = 3;
複製代碼
  • index: 表示經過索引進行全表掃描和 ALL 類型相似, 有點是避免了排序,肯定是須要承擔按照索引次序讀取表的開銷。若是 Extra 列中出現了 「Using index」 代表是用了覆蓋索引,此時開銷很是小。
  • ALL: 表示全表掃描, 這個類型的查詢是性能最差的查詢之一。通常狀況下都會從頭至尾掃描全部行,除非使用了 Limit 或者 Extra 列中顯示 「Using distinct/not exists」。
possible_keys

這次查詢中可能選用的索引,這些索引列是根據查詢的列以及比較操做符來判斷的,可能在後續的真實查詢中沒有用到也有可能性能

key

這次查詢中確切使用到的索引,若是在 possible_keys 中沒有出現而在 key 中出現,說明優化器可能出於另外緣由好比選擇覆蓋索引,因此 possiable_keys 揭示了哪個索引有助於高效進行查找,而 key 顯示了採用哪個索引能夠最小化查詢成本。學習

key_len

表示查詢優化器使用了索引的字節數. 這個字段能夠評估組合索引是否徹底被使用, 或只有最左部分字段被使用到,好比咱們建了一個組合索引(col1, col2),那麼以下兩條查詢雖然用到的都是這個組合索引,可是對應的key_len的只是不同的。key_len 顯示了在索引字段中可能的最大長度,而不是數據使用的實際字節數優化

select * from table1 where col1 = 1;
select * from table1 where col1 = 1 and col2 = 2;
複製代碼
ref

這一列顯示了以前的表在 key 列記錄的索引中查找值所用的列或者常量ui

rows

rows 也是一個重要的字段. MySQL 查詢優化器根據統計信息, 估算 SQL 要查找到結果集須要掃描讀取的數據行數。這個值很是直觀顯示 SQL 的效率好壞, 原則上 rows 越少越好。

  • 經過把每一個表的 rows 值相乘能夠粗略的估算出整個查詢要檢查的行數
  • 這個值只是一個估算的值,不是實際查出來的值
filtered

filtered 是在 MYSQL 5.1 中加進來的,在使用 EXPLAIN EXTENDED 時出現,表示此查詢條件所過濾的數據的百分比,將 rows 除以 filtered 能夠估算出整個表數據行數。

Extra

EXplain 中的不少額外的信息會在 Extra 字段顯示, 常見的有如下幾種內容:

  • Using filesort

當 Extra 中有 Using filesort 時, 表示 MySQL 需額外的排序操做, 不能經過索引順序達到排序效果. 通常有 Using filesort, 都建議優化去掉, 由於這樣的查詢 CPU 資源消耗大。 可是 Explain 不會告訴你 Mysql 將使用文件排序仍是內存排序:

-- 好比咱們創建索引爲:KEY `user_product_detail_index` (`user_id`, `product_name`, `productor`),那麼以下兩個查詢

EXPLAIN SELECT * FROM order_info ORDER BY product_name;    -- Using filesort,不能經過索引進行排序,須要優化
EXPLAIN SELECT * FROM order_info ORDER BY user_id, product_name;-- 無 Using filesort,經過索引進行排序,優化成功
複製代碼
  • Using index

"覆蓋索引掃描", 表示查詢在索引樹中就可查找所需數據, 不用掃描表數據文件, 每每說明性能不錯

  • Using where

這意味着 Mysql 服務器在存儲引擎檢索行後再進行過濾,通常出現 「Using where」 會受益於不一樣的索引

  • Using temporary

查詢有使用臨時表, 通常出現於排序, 分組和多表 join 的狀況, 臨時表多是內存臨時表或者文件臨時表

partitions

在 Mysql 5.1 版本中引入了 EXPLAIN PARTITIONS 能夠顯示查詢將訪問的分區狀況

參考文獻

相關文章
相關標籤/搜索