MySQL性能分析方法


MYSQL 性能分析方法

1、性能優化概述

MySQL Query Optimizer 的作用

  1. MySQL 中有專門負責優化SELECT語句的優化器模塊,主要功能:通過計算分析系統中收集到的統計信息,為客戶端請求的Query提供他認為最優的執行計划(MySQL認為最優的數據檢索方式,但不見得是DBA認為是最優的,這部分最耗費時間)
  2. 當客戶端向MySQL 請求一條Query,命令解析器模塊完成請求分類,區別出是SELECT並轉發給MySQL Query Optimizer時,MySQL Query Optimizer 首先會對整條Query進行優化,處理掉一些常量表達式的預算,直接換算成常量值。並對Query中的查詢條件進行簡化和轉換,如去掉一些無用或顯而易見的條件、結構調整等。然后分析 Query中的Hint信息(如果有),看顯示Hint信息是否可以完全確定該Query的執行計划。如果沒有Hint 或Hint 信息還不足以完全確定執行計划,則會讀取所涉及對象的統計信息,根據Query進行寫相應的計算分析,然后再得出最后的執行計划。

MySQL 常見瓶頸

  1. CPU 瓶頸:CPU在飽和的時候一般發生在數據裝入在內存或從磁盤上讀取數據時候
  2. IO 瓶頸:磁盤I/O瓶頸發生在裝入數據遠大於內存容量時
  3. 服務器硬件的性能瓶頸:top、free、iostat和vmstat來查看系統的性能狀態

2、Explain 概述

Explain

是什么#?Explain 是查看執行計划

  1. 使用EXPLAIN關鍵字可以模擬優化器執行SQL語句,從而知道MySQL是如何處理你的SQL語句的。分析你的查詢語句或是結構的性能瓶頸
  2. 官網地址:https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

能干嘛?

  1. 表的讀取順序(id 字段)
  2. 數據讀取操作的操作類型(select_type 字段)
  3. 哪些索引可以使用(possible_keys 字段)
  4. 哪些索引被實際使用(keys 字段)
  5. 表之間的引用(ref 字段)
  6. 每張表有多少行被優化器查詢(rows 字段)

怎么玩?

  • Explain + SQL語句
mysql> explain select * from tbl_emp;
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | tbl_emp | ALL  | NULL          | NULL | NULL    | NULL |    8 | NULL  |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)

3、Explain 詳解

id☆

id:select查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序

id 取值的三種情況:

  1. id相同,執行順序由上至下

    image-20200804101016101

  2. id不同,如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行

    image-20200804101005684

  3. id相同不同,同時存在:id如果相同,可以認為是一組,從上往下順序執行;在所有組中,id值越大,優先級越高,越先執行;衍生=DERIVED

    image-20200804101502048

select_type

select_type:查詢的類型,主要用於區別普通查詢、聯合查詢、子查詢等復雜查詢

  1. SIMPLE:簡單的select查詢,查詢中不包含子查詢或者UNION
  2. PRIMARY:查詢中若包含任何復雜的子部分,最外層查詢則被標記為PRIMARY
  3. SUBQUERY:在SELECT或者WHERE列表中包含了子查詢
  4. DERIVED:在FROM列表中包含的子查詢被標記為DERIVED(衍生)MySQL會遞歸執行這些子查詢,把結果放在臨時表里
  5. UNION:若第二個SELECT出現在UNION之后,則被標記為UNION;若UNION包含在FROM子句的子查詢中,外層SELECT將被標記為:DERIVED
  6. UNION RESULT:從UNION表獲取結果的SELECT

UNION 和 UNION RESULT舉例

xplain
    -> select * from tbl_emp e left join tbl_dept d on e.deptId = d.id
    -> union
    -> select * from tbl_emp e right join tbl_dept d on e.deptId = d.id;
+----+--------------+------------+------+---------------+------------+---------+-----------+------+----------------------------------------------------+
| id | select_type  | table      | type | possible_keys | key        | key_len | ref       | rows | Extra                                              |
+----+--------------+------------+------+---------------+------------+---------+-----------+------+----------------------------------------------------+
|  1 | PRIMARY      | e          | ALL  | NULL          | NULL       | NULL    | NULL      |    8 | NULL                                               |
|  1 | PRIMARY      | d          | ALL  | PRIMARY       | NULL       | NULL    | NULL      |    5 | Using where; Using join buffer (Block Nested Loop) |
|  2 | UNION        | d          | ALL  | NULL          | NULL       | NULL    | NULL      |    5 | NULL                                               |
|  2 | UNION        | e          | ref  | fk_dept_Id    | fk_dept_Id | 5       | db01.d.id |    1 | NULL                                               |
| NULL | UNION RESULT | <union1,2> | ALL  | NULL          | NULL       | NULL    | NULL      | NULL | Using temporary                                    |
+----+--------------+------------+------+---------------+------------+---------+-----------+------+----------------------------------------------------+
5 rows in set (0.00 sec)

table

table:顯示這一行的數據是關於哪張表的

type☆

type:訪問類型排列,顯示查詢使用了何種類型

  1. type顯示的是訪問類型,是較為重要的一個指標,結果值從最好到最壞依次是:system>const>eq_ref>ref>fultext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL
  2. 挑重要的來說:system>const>eq_ref>ref>range>index>ALL,一般來說,得保證查詢至少達到range級別,最好能達到ref。

從最好到最差依次是:system>const>eq_ref>ref>range>index>ALL

  1. system:表只有一行記錄(等於系統表),這是const類型的特例,平時不會出現,這個也可以忽略不計

  2. const:表示通過索引一次就找到了,const用於比較primary key或者unique索引。因為只匹配一行數據,所以很快。如將主鍵置於where列表中,MySQL就能將該查詢轉換為一個常量

    image-20200804103028065

  3. eq_ref:唯一性索引,對於每個索引鍵,表中只有一條記錄與之匹配,常見於主鍵或唯一索引掃描

    image-20200804103543783

  4. ref:非唯一索引掃描,返回匹配某個單獨值的所有行。本質上也是一種索引訪問,它返回所有匹配某個單獨值的行,然而,它可能會找到多個符合條件的行,所以他應該屬於查找和掃描的混合體

    image-20200804103959011

  5. range:只檢索給定范圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引一般就是在你的where語句中出現了between<>in等的查詢這種范圍掃描索引掃描比全表掃描要好,因為他只需要開始索引的某一點,而結束於另一點,不用掃描全部索引

    image-20200804104130086

  6. index:Full Index Scan,index與ALL區別為index類型只遍歷索引樹。這通常比ALL快,因為索引文件通常比數據文件小。(也就是說雖然all和index都是讀全表,但index是從索引中讀取的,而all是從硬盤數據庫文件中讀的

    image-20200804104254208

  7. all:FullTable Scan,將遍歷全表以找到匹配的行(全表掃描)

    image-20200804104358142

  8. 備注:一般來說,得保證查詢只是達到range級別,最好達到ref

possible_keys

possible_keys

  1. 顯示可能應用在這張表中的索引,一個或多個
  2. 若查詢涉及的字段上存在索引,則該索引將被列出,但不一定被查詢實際使用

key

key

  1. 實際使用的索引,如果為null,則沒有使用索引

  2. 若查詢中使用了覆蓋索引,則該索引僅出現在key列表中

    image-20200804105225100

key_len

key_len

  1. 表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度。在不損失精確性的情況下,長度越短越好
  2. key_len顯示的值為索引最大可能長度,並非實際使用長度,即key_len是根據表定義計算而得,不是通過表內檢索出的

image-20200804105833936
image-20200804105833936

ref

ref

  1. 顯示索引哪一列被使用了,如果可能的話,最好是一個常數。哪些列或常量被用於查找索引列上的值
  2. 由key_len可知t1表的索引idx_col1_col2被充分使用,t1表的col1匹配t2表的col1,t1表的col2匹配了一個常量,即’ac’

image-20200804110346982
image-20200804110346982

rows

rows

根據表統計信息及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數

image-20200804111249713
image-20200804111249713

Extra☆

Extra:包含不適合在其他列中顯示但十分重要的額外信息

  1. Using filesort(文件排序):

    • MySQL中無法利用索引完成排序操作成為“文件排序”
    • 說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取
    • 出現 Using filesort 不好(九死一生),需要盡快優化 SQL
    • 示例中第一個查詢只使用了 col1 和 col3,原有索引派不上用場,所以進行了外部文件排序
    • 示例中第二個查詢使用了 col1、col2 和 col3,原有索引派上用場,無需進行文件排序

    image-20200804111738931

  2. Using temporary(創建臨時表):

    • 使用了臨時表保存中間結果,MySQL在對查詢結果排序時使用臨時表。常見於排序 order by 和分組查詢 group by
    • 出現 Using temporary 超級不好(十死無生),需要立即優化 SQL
    • 示例中第一個查詢只使用了 col1,原有索引派不上用場,所以創建了臨時表進行分組
    • 示例中第二個查詢使用了 col1、col2,原有索引派上用場,無需創建臨時表

    image-20200804112558915

  3. Using index(覆蓋索引):

    • 表示相應的select操作中使用了覆蓋索引(Coveing Index),避免訪問了表的數據行,效率不錯!

    • 如果同時出現using where,表明索引被用來執行索引鍵值的查找

    • 如果沒有同時出現using where,表明索引用來讀取數據而非執行查找動作

    image-20200804113450147

    • 覆蓋索引(Covering Index),也說為索引覆蓋

      - 理解方式一:就是**select的數據列只用從索引中就能夠取得,不必讀取數據行**,MySQL可以**利用索引返回select列表中的字段,而不必根據索引再次讀取數據文件**,換句話說查詢列要被所建的索引覆蓋。
      - 理解方式二:索引是高效找到行的一個方法,但是一般數據庫也能使用索引找到一個列的數據,因此它不必讀取整個行。畢竟索引葉子節點存儲了它們索引的數據;當能通過讀取索引就可以得到想要的數據,那就不需要讀取行了。一個索引包含了(或覆蓋了)滿足查詢結果的數據就叫做覆蓋索引。
      - 注意:**如果要使用覆蓋索引,一定要注意select列表中只取出需要的列,不可`select *`** ,因為如果將所有字段一起做索引會導致索引文件過大,查詢性能下降。
  4. Using where:表明使用了where過濾

  5. Using join buffer:表明使用了連接緩存

  6. impossible where:where子句的值總是false,不能用來獲取任何元組

    image-20200804113946144

  7. select tables optimized away:在沒有GROUPBY子句的情況下,基於索引優化MIN/MAX操作或者對於MyISAM存儲引擎優化COUNT(*)操作,不必等到執行階段再進行計算,查詢執行計划生成的階段即完成優化。

  8. distinct:優化distinct,在找到第一匹配的元組后即停止找同樣值的工作

轉自此文章B站此視頻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM