《高性能MySQL》EXPLAIN

前言

調用 EXPLAIN 來獲取關於查詢執行計劃的信息與輸出

調用 EXPLAIN

  1. 使用:在 SELECT 關鍵字之前增加 EXPLAIN
    image-20190127172115882

  2. 每個表在輸出中只有一行,若多表關聯,則輸出多行

  • 這裏的表的定義:可以是一個子查詢,一個 UNION 結果
  • EXPLAIN 的兩個主要變種
    • EXPLAIN EXTENDED
      • 服務器 “逆向編譯” 執行計劃爲一個 SELECT 語句(SHOW WARNINGS 後能看到
      • 額外增加一個 filtered 列
    • EXPLAIN PARTITIONS
      • 顯示查詢將訪問的分區
  1. EXPLAIN 查詢時,會執行子查詢並將其結果放在一個臨時表中,然後完成外層查詢優化

  2. EXPLAIN 返回的只是個近似結果

  3. EXPLAIN 相關的限制

  • 無法知道觸發器、存儲過程或 UDF 如何影響查詢

  • 不支持存儲過程(單可以單獨抽取查詢進行 EXPLAIN

  • 無法知道查詢執行中所做的特定優化

  • 不會顯示關於查詢的執行計劃的所有信息

  • 無法區分具有相同名字的事物

    • 內存排序 和 臨時文件 都使用 filesort
    • 磁盤上和內存中的臨時表都顯示 Using temporary
  • 可能會誤導(對一個有着小 LIMIT 的查詢顯示 全索引掃描

重寫非 SELECT 查詢

  1. EXPLAIN 只能解釋 SELECGT 查詢,無法對 INSERT、UPDATE、DELETE 或其他語句做解釋

  2. 可通過重寫某些非 SELECT 查詢以利用 EXPLAIN

    • 轉化成一個等價的訪問所有相同列的 SELECT
    • 任何提及的列都必須在 SELECT 列表,關聯子句 或者 WHERE 子句中
  3. 顯示計劃時,對於寫查詢並沒有“等價”的讀查詢

    • 讀只需要找到數據的一份副本並返回
    • 寫需要查找並修改其所有副本(消耗更高

EXPLAIN 中的列

  1. id 列

    • 總是包含一個編碼,標識 SELECT 所屬的行

    • 簡單查詢類型

    • 複雜查詢類型

      • 簡單子查詢
      • 派生表
      • UNION
    • UNION 結果總是放在一個匿名臨時表中(它的 id 列是 NULL

  2. select_type 列

    • SIMPLE
      • 不包括子查詢和 UNION
    • PRIMARY
      • 查找中存在複雜的子部分,最外層部分標記爲 PRIMARY
    • SUBQUERY
      • SELECT 列表中的子查詢中的 SELECT
    • DERIVED
      • FROM 子句的子查詢中的 SELECT(派生表
    • UNION
      • 在 UNION 中的第二個和隨後的 SELECT 被標記爲 UNION
    • UNION RESULT
      • 從 UNION 的匿名臨時表檢索結果的 SELECT
    • DEPENDENT
      • SELECT 依賴與外層查詢中發現的數據
    • UNCACHEABLE
      • SELECT 中的某些特性阻止結果被緩存於一個 Item_cache 中
  3. table 列

    • 顯示對應行正在訪問哪個表
    • MySQL 的查詢執行計劃總是左側深度優先樹
      image-20190127185947881
  4. type 列

    • 顯示了 關聯類型(訪問類型
    • 常用的訪問類型(性能依次從最差到最優
      • ALL
        • 全表掃描(存在例外,例如使用了 LIMIT 或 Extra 列中顯示 Using distinct/not exists
      • index
        • 類似於全表掃描,只是掃描時按索引次序進行
        • 優點:可以避免排序
        • 缺點:承擔按索引次序讀取整個表的開銷(意味着按隨機次序訪問行,開銷較大
      • range
        • 有限制的索引掃描(範圍掃描
        • IN ( ) 和 OR 列表使用時均顯示爲 範圍掃描,但兩者其實是相當不同的訪問類型,性能差異較大
      • ref
        • 索引訪問(索引查找),返回所有匹配某個單個值的行
        • 使用場景:使用非唯一索引時 或 唯一索引的非唯一性前綴時
        • ref_or_null(變體):MySQL 必須在初次查找的結果裏進行第二次查找以找出 NULL 條目
      • eq_ref
        • 最多隻返回一條符合條件的記錄
        • 使用場景:使用主鍵 或 唯一索引時
      • const ,system
        • MySQL 能對查詢的某部分進行優化並將其轉換成一個常量時
      • NULL
        • MySQL 能再優化階段分解查詢語句,在執行階段甚至用不着再訪問表或者索引
  5. possible_keys 列

    • 顯示查詢可能使用哪些索引
  6. key 列

    • 顯示 MySQL 決定採用哪個索引來優化對該表的訪問(基於最小化查詢成本
    • 該索引可能不存在 possible_keys 列中(可能選擇了一個覆蓋索引,哪怕沒有 WHERE 子句
  7. key_len 列

    • 顯示 MySQL 在索引裏使用的字節數(具體使用到的該索引上的某些列
    • key_len 通過查找表的定義而被計算出,而不是表中的數據
  8. ref 列

    • 顯示在 key 列記錄的索引中查找值所用的列或常量
  9. rows 列

    • 顯示 MySQL 估計爲了找到所需要的行而要讀取的行數(嵌套循環管理計劃裏的嵌套數目
    • 該數字只是 MySQL 認爲它要檢查的行數,而不是結果集裏的行數
  10. filtered 列

- 使用 EXPLAIN EXTEND 時纔會出現
- 顯示 針對表裏符合某個條件的記錄數的百分比所做的一個悲觀估算
  - 只有在使用 ALL、index、range 和 index_merge 訪問時纔會用到這一估算
  1. Extra 列
  • 顯示不適合在其他列顯示的額外信息
  • 常見重要的值
    • Using index(覆蓋索引
    • Using where(Mysql 服務器將在存儲引擎檢索後再進行過濾
    • Using temporary(對查詢結果排序時會使用一個臨時表
    • Using filesort(對結果使用一個外部索引排序,詳情請看:《高性能 MySQL》查詢性能優化
    • Range checked for each record(沒有好用的索引,新索引將在聯接的每一行上重新估算

MySQL 5.6 中的改進

  • 能對類似於 UPDATE、INSERT等的查詢進行解釋
  • 對查詢優化和執行引擎的一系列改進
    • 允許匿名的臨時表儘可能晚地被具體化
    • 可直接解釋帶子查詢的查詢語句,而不需要先實際地執行子查詢
  • 增加優化跟蹤功能的方式改進優化器
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章