Spring+SpringMVC+MyBatis+easyUI整合優化篇(十二)數據層優化-explain關鍵字及慢sql優化


本文提要

從編碼角度來優化數據層的話,我首先會去查一下項目中運行的sql語句,定位到瓶頸是否出現在這里,首先去優化sql語句,而慢sql就是其中的主要優化對象,對於慢sql,顧名思義就是花費較多執行時間的語句,它帶來的影響也比較惡劣,首先是執行時間過長影響數據的返回速度,其次,慢sql的長時間執行也會消耗和占用mysql的系統資源,影響其他的sql語句執行,過多的慢sql極其影響性能,如果系統流量或者並發量較大的情況下,過多的執行慢sql很有可能造成mysql的死鎖以致於mysql服務無法正常使用。
druid整合到項目中以及druid監控的開啟已經持續了一段時間,因此對於慢sql的監控和整理也大致有了一些結果,本篇文章就試着從日志文件和監控面板中找出幾條慢sql並進行優化。

優化步驟

總結了一下,大致步驟如下:

  • 定位優化對象的性能瓶頸;
  • 明確優化目標;
  • 從explain入手分析;
  • 找到優化方法;

找出慢sql

首先進入druid監控后台,查看一下這幾天的運行日志后,慢sql的大致情況,如圖:
慢sql監控

從監控后台看到的數據只是一個粗略的統計,是一個總覽記錄,想要看到詳細的執行記錄及其中的慢sql統計可以通過日志文件,這個功能也已經整合到項目中,直接在tomcat的logs目錄即可查看。
慢sql日志文件

日志文件內容節選:

//1.圖片表查詢sql
[10:13:37] StatFilter - slow sql 1572 millis. 
select * from ssm_picture
         WHERE  type = ? and grade = ?          
 limit ?,?
["1","1",0,10]

...
//2.更新文章表sql
[14:19:12] StatFilter - slow sql 1926 millis. 
update ssm_article
		set
		article_title=?,article_content=?,
		add_name=?
		where id=?
["11","<p>1324354657usdfghjnkm,zxvb nm,,fgfhjtfggggggggggggggggggg<br/></p>","22","1033"]

...

//3.文章表查詢sql
[15:07:04] StatFilter - slow sql 1672 millis. 
select * from ssm_article
limit ?,?
[0,10]

日志的記錄格式為 [執行時間] -慢sql執行耗時 ,sql語句,其實日志中記錄是挺多的,去重之后從日志文件中單獨選了幾條比較典型的sql語句進行優化。

explain關鍵字

explain關鍵字一般放在SELECT查詢語句的前面,用於描述MySQL如何執行查詢操作、以及MySQL成功返回結果集需要執行的行數。explain 可以幫助我們分析 select 語句,讓我們知道查詢效率低下的原因,從而改進我們查詢,讓查詢優化器能夠更好的工作。

用法:
explain-01

結果集說明如下:

說明
id MySQL Query Optimizer選定的執行計划中查詢的序列號。表示查詢中執行select子句或操作表的順序,id值越大優先級越高,越先被執行。id相同,執行順序由上至下。

select_type 查詢類型 說明
SIMPLE 簡單的select查詢,不使用union及子查詢。
PRIMARY 最外層的select查詢。
UNION UNION 中的第二個或隨后的 select查詢,不依賴於外部查詢的結果集。
DEPENDENT UNION UNION中的第二個或隨后的 select查詢,依 賴於外部查詢的結果集。
SUBQUERY 子查詢中的第一個select查詢,不依賴於外部查詢的結果集。
DEPENDENT SUBQUERY 子查詢中的第一個select查詢,依賴於外部查詢的結果集。
DERIVED 用於from子句里有子查詢的情況。MySQL會遞歸執行這些子查詢,把結果放在臨時表里。
UNCACHEABLE SUBQUERY 結果集不能被緩存的子查詢,必須重新為外層查詢的每一行進行評估。
UNCACHEABLE UNION UNION中的第二個或隨后的select查詢,屬於不可緩存的子查詢。

說明
table 輸出行所引用的表

type 顯示連接使用的類型,按最優到最差的類型排序 說明
system 表僅有一行(=系統表)。這是const連接類型的一個特例。
const const用於用常數值比較PRIMARY KEY時。當查詢的表僅有一行時,使用System。
eq_ref const用於用常數值比較PRIMARY KEY時。當查詢的表僅有一行時,使用System。
ref 連接不能基於關鍵字選擇單個行,可能查找到多個符合條件的行。叫做ref是因為索引要跟某個參考值相比較。這個參考值或者是一個常數,或者是來自一個表里的多表查詢的結果值
ref_or_null 如同ref, 但是MySQL必須在初次查找的結果里找出null條目,然后進行二次查找。
index_merge 說明索引合並優化被使用了。
unique_subquery 在某些IN查詢中使用此種類型,而不是常規的ref:value IN (SELECT primary_key FROM single_table WHERE some_expr)
index_subquery 在某些IN查詢中使用此種類型,與unique_subquery類似,但是查詢的是非唯一性索引:value IN(SELECT key_column FROM single_table WHERE some_expr)
range 只檢索給定范圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引。當使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比較關鍵字列時,可以使用range。
index 全表掃描,只是掃描表的時候按照索引次序進行而不是行。主要優點就是避免了排序,但是開銷仍然非常大。
all 最壞的情況,從頭到尾全表掃描。

說明
possible_keys 指出MySQL能在該表中使用哪些索引有助於查詢。如果為空,說明沒有可用的索引。

說明
key MySQL實際從possible_key選擇使用的索引。如果為NULL,則沒有使用索引。很少的情況下,MYSQL 會選擇優化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX (indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MYSQL忽略索引

說明
key_len 使用的索引的長度。在不損失精確性的情況下,長度越短越好。

說明
ref 顯示索引的哪一列被使用了

說明
rows MYSQL認為必須檢查的用來返回請求數據的行數

extra 中出現以下2項意味着MYSQL根本不能使用索引,效率會受到重大影響。應盡可能對此進行優化。

extra項 說明
Using filesort 表示MySQL會對結果使用一個外部索引排序,而不是從表里按索引次序讀到相關內容。可能在內存或者磁盤上進行排序。MySQL中無法利用索引完成的排序操作稱為“文件排序”
Using temporary 表示MySQL在對查詢結果排序時使用臨時表。常見於排序order by和分組查詢 group by。

優化目標

優化的目標是一定要明確的,不然根本無從下手,針對於前文中提到的sql語句,及explain關鍵字的解釋,我列出了兩條目標:

  • 避免全表掃描
  • rows參數盡量減小

至於為什么只列出這兩條目標,主要是因為項目中並沒有復雜的邏輯,也也沒有復雜的查詢,建表時也並沒有根據相關查詢創建索引,而且數據量也不大,因此能夠優化的點並不是太多,即使做了優化也不能顯著的提升速度及性能,因此就先列了兩個簡單的小目標,先體驗一下explain關鍵字在sql優化中的作用。

優化

針對第2條更新文章sql,執行時間較長的原因主要是因為數據量太大,應該是一個朋友在測試的時候做的操作,article_content字段插入了一條20萬字符大小的數據,因此,主要問題在於插入數據過大,代碼已經更新了參數檢查功能,在程序中做了限制。

對於另外兩條查詢語句,首先用explain分析sql語句,如下:
ssm_article

ssm_picture

注意其中的兩個參數,type都是all,rows較小,都為總記錄,我們的兩個目標是什么?type不能為all,rows盡量小,這里似乎滿足了一個條件,其實不然,因為這兩個表的數據量小,因此rows值也小,如果換一張表(book表較大),以相同格式執行一條sql得到如下結果:
ssm_book

rows為416,並沒有因為使用了limit關鍵字而返回較小的值,因此兩條sql都需要做一下簡單的優化。

幾張表都沒有創建索引,是不是就沒有索引了呢?其實不然,你可能忽略了一點,就是主鍵索引,索引的知識點在接下來一篇文章中會寫,這一篇就簡單的提一下,因此優化策略就是使用主鍵索引,將type由all變為index,稍微優化了一點點,改寫后的sql語句如下,分析結果如下:
ssm_book

通過與上面的結果對比,可以看到rows值也變小了。
ssm_picture

ssm_article

type由all全部變為index。

總結

由於項目比較簡單,都是操作單表的sql語句,沒有復雜查詢,也沒有多表的連接查詢,速度提升並沒有太多,對於目前的項目來說,不會有特別大的優化動作,如果以后有機會再去結合實際案例去優化,現在就點到為止了,這一篇主要是介紹一下druid監控的成果以及mysql查詢優化的explain關鍵字,因此並沒有做太多的案例及分析,只是做了一些小修改,使得大家對explain關鍵字有了一些了解,下一篇會繼續做一些優化改動。


免責聲明!

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



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