1. 程式人生 > 其它 >Spring+SpringMVC+MyBatis+easyUI整合優化篇(十二)資料層優化-explain關鍵字及慢sql優化

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統計可以通過日誌檔案,這個功能也已經整合到專案中,直接在tomcat的logs目錄即可檢視。

日誌檔案內容節選:

//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 語句,讓我們知道查詢效率低下的原因,從而改進我們查詢,讓查詢優化器能夠更好的工作。

用法:

結果集說明如下:

說明

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語句,如下:

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

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

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

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

type由all全部變為index。

總結

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