mysql高級教程(二)-----性能分析


MySQL常見瓶頸

1、cpu

SQL中對大量數據進行比較、關聯、排序、分組

2、IO

a、實例內存滿足不了緩存數據或排序等需要,導致產生大量物理 IO。

b、查詢執行效率低,掃描過多數據行。

3、鎖

a、不適宜的鎖的設置,導致線程阻塞,性能下降。

b、死鎖,線程之間交叉調用資源,導致死鎖,程序卡住。

4、服務器硬件的性能瓶頸

top,free, iostat和vmstat來查看系統的性能狀態

Explain(執行計划)

概念

使用EXPLAIN關鍵字可以模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的,分析你的查詢語句或是表結構的性能瓶頸。

能干嘛

  • 表的讀取順序
  • 哪些索引可以使用
  • 數據讀取操作的操作類型
  • 哪些索引被實際使用
  • 表之間的引用
  • 每張表有多少行被優化器查詢

使用方法

Explain + SQL語句

explain select * from tb1_emp;

字段解釋

id

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

示例:

三種情況:

  • id相同,執行順序由上至下-----id相同,執行順序由上至下  此例中 先執行where 后的第一條語句 t1.id = t2.id 通過 t1.id 關聯 t2.id 。 而  t2.id 的結果建立在 t2.id=t3.id 的基礎之上。 
  • id不同,如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行-----  id不同,如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行  
  • id相同不同,同時存在-----    id如果相同,可以認為是一組,從上往下順序執行;在所有組中,id值越大,優先級越高,越先執行 衍生表 = derived2 --> derived + 2 (2 表示由 id =2 的查詢衍生出來的表。type 肯定是 all ,因為衍生的表沒有建立索引)

select_type 

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

常用類型:

SIMPLE

簡單的 select 查詢,查詢中不包含子查詢或者UNION

PRIMARY 

查詢中若包含任何復雜的子部分,最外層查詢則被標記為Primary 

DERIVED

在FROM列表中包含的子查詢被標記為DERIVED(衍生).MySQL會遞歸執行這些子查詢, 把結果放在臨時表里。 -----DERIVED 既查詢通過子查詢查出來的 臨時表

SUBQUERY 

在SELECT或WHERE列表中包含了子查詢

DEPENDENT SUBQUERY

在SELECT或WHERE列表中包含了子查詢,子查詢基於外層-----dependent subquery 與 subquery 的區別依賴子查詢 : 子查詢結果為多值子查詢:查詢結果為單值 

UNCACHEABLE SUBQUREY

無法被緩存的子查詢

UNION

若第二個SELECT出現在UNION之后,則被標記為UNION;若UNION包含在FROM子句的子查詢中,外層SELECT將被標記為:DERIVED-----UNION RESULT 兩個語句執行完后的結果

UNION RESULT

從UNION表獲取結果的SELECT從UNION表獲取結果的SELECT

table

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

type

顯示查詢使用了何種類型,是較為重要的一個指標,結果值從最好到最壞依次是:  system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range(盡量保證) > index > ALL

從最好到最差依次是(通常記下面這個):
system>const>eq_ref>ref>range>index>ALL

 一般來說,得保證查詢至少達到range級別,最好能達到ref。

possible_keys

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

key

實際使用的索引。如果為NULL,則沒有使用索引。

key_len

表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度。能夠幫你檢查是否充分的利用上了索引。在不損失精度的情況下,越短越好。

ref

顯示索引的哪一列被使用了,如果可能的話,是一個常數。哪些列或常量被用於查找索引列上的值。

rows

rows列顯示MySQL認為它執行查詢時必須檢查的行數。

Extra

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

索引優化

索引失效

避免索引失效則是查詢優化

1、全值匹配我最愛

當建立復合索引時。比如a、b、c三個字段,最好查詢的時候帶上a、b、c,並且a一定要有,帶頭大哥不能死,否則全表掃描。(結合下面的最佳左前綴法則)

2、最佳左前綴法則

如果索引了多列(復合索引或叫聯合索引),要遵守最左前綴法則。指的是查詢從索引的最左前列開始並且不跳過索引中的列。-----中間兄弟不能斷

3、不在索引列上做任何操作(計算、函數、(自動or手動)類型轉換),會導致索引失效而轉向全表掃描。-----索引列上無計算

4、存儲引擎不能使用索引中范圍條件右邊的列-----若有索引則能使用到索引,范圍條件右邊的索引會失效(范圍條件右邊與范圍條件使用的同一個組合索引,右邊的才會失效。若是不同索引則不會失效)-----范圍之后全失效

對於上例,age以及pos的索引都不能使用。

 5、盡量使用覆蓋索引(只訪問索引的查詢(索引列和查詢列一致)),減少select *。

 6、mysql 在使用不等於(!= 或者<>)的時候無法使用索引會導致全表掃描

 7、is null、is not null 也無法使用索引

 8、like以通配符開頭('%abc...')mysql索引失效會變成全表掃描的操作-----%寫在右邊可以避免全表掃描。或者使用覆蓋索引(比如name、age建了索引,只查詢這兩列的值出來,並且順序也要一樣)

9、字符串不加單引號索引失效 ----- 底層進行轉換使索引失效,使用了函數造成索引失效(隱式轉換)

10、少用or,用它來連接時會索引失效 

案例總結: 

 

一般性建議

1、對於單鍵索引,盡量選擇針對當前query過濾性更好的索引

2、在選擇組合索引的時候,當前Query中過濾性最好的字段在索引字段順序中,位置越靠左越好。(避免索引過濾性好的索引失效)

3、在選擇組合索引的時候,盡量選擇可以能夠包含當前query中的where字句中更多字段的索引

4、盡可能通過分析統計信息和調整query的寫法來達到選擇合適索引的目的

查詢優化 

永遠小表驅動大表

即小的數據集驅動大的數據集。

order by關鍵字排序優化

1、ORDER BY子句,盡量使用Index方式排序,避免使用FileSort方式排序

MySQL支持二種方式的排序,FileSort和Index,Index效率高.它指MySQL掃描索引本身完成排序。FileSort方式效率較低。

ORDER BY滿足兩情況,會使用Index方式排序:

  • a、ORDER BY 語句使用索引最左前列
  • b、使用Where子句與Order BY子句條件列組合滿足索引最左前列

注:where子句中如果出現索引的范圍查詢(即explain中出現range)會導致order by 索引失效。

2、盡可能在索引列上完成排序操作,遵照索引建的最佳左前綴

 

group by關鍵字排序優化 

1、group by實質是先排序后進行分組,遵照索引建的最佳左前綴 

2、當無法使用索引列,增大max_length_for_sort_data參數的設置+增大sort_buffer_size參數的設置

3、 where高於having,能寫在where限定的條件就不要去having限定了。

慢查詢日志 

概念

MySQL的慢查詢日志是MySQL提供的一種日志記錄,它用來記錄在MySQL中響應時間超過閥值的語句,具體指運行時間超過long_query_time值的SQL,則會被記錄到慢查詢日志中。 具體指運行時間超過long_query_time值的SQL,則會被記錄到慢查詢日志中。long_query_time的默認值為10,意思是運行10秒以上的語句。 由他來查看哪些SQL超出了我們的最大忍耐時間值,比如一條sql執行超過5秒鍾,我們就算慢SQL,希望能收集超過5秒的sql,結合之前explain進行全面分析。 

使用方式 

默認情況下,MySQL數據庫沒有開啟慢查詢日志,需要我們手動來設置這個參數。當然,如果不是調優需要的話,一般不建議啟動該參數,因為開啟慢查詢日志會或多或少帶來一定的性能影響。慢查詢日志支持將日志記錄寫入文件 

默認:

SHOW VARIABLES LIKE '%slow_query_log%';

開啟:

set global slow_query_log=1;

如何判斷是慢sql

這個是由參數long_query_time控制,默認情況下long_query_time的值為10秒,命令:SHOW VARIABLES LIKE 'long_query_time%';可以使用命令修改,也可以在my.cnf參數里面修改。假如運行時間正好等於long_query_time的情況,並不會被記錄下來。也就是說,在mysql源碼里是判斷大於long_query_time,而非大於等於。 

查詢多少條慢sql

  show global status like '%Slow_queries%';  

mysqldumpslow

在生產環境中,如果要手工分析日志,查找、分析SQL,顯然是個體力活,MySQL提供了日志分析工具mysqldumpslow。

mysqldumpslow --help

 


免責聲明!

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



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