本文提要
從編碼角度來(lái)優(yōu)化數(shù)據(jù)層的話,我首先會(huì)去查一下項(xiàng)目中運(yùn)行的sql語(yǔ)句润脸,定位到瓶頸是否出現(xiàn)在這里毙驯,首先去優(yōu)化sql語(yǔ)句爆价,而慢sql就是其中的主要優(yōu)化對(duì)象允坚,對(duì)于慢sql稠项,顧名思義就是花費(fèi)較多執(zhí)行時(shí)間的語(yǔ)句展运,它帶來(lái)的影響也比較惡劣拗胜,首先是執(zhí)行時(shí)間過(guò)長(zhǎng)影響數(shù)據(jù)的返回速度埂软,其次勘畔,慢sql的長(zhǎng)時(shí)間執(zhí)行也會(huì)消耗和占用mysql的系統(tǒng)資源炫七,影響其他的sql語(yǔ)句執(zhí)行万哪,過(guò)多的慢sql極其影響性能奕巍,如果系統(tǒng)流量或者并發(fā)量較大的情況下的止,過(guò)多的執(zhí)行慢sql很有可能造成mysql的死鎖以致于mysql服務(wù)無(wú)法正常使用冲杀。
druid整合到項(xiàng)目中以及druid監(jiān)控的開啟已經(jīng)持續(xù)了一段時(shí)間权谁,因此對(duì)于慢sql的監(jiān)控和整理也大致有了一些結(jié)果旺芽,本篇文章就試著從日志文件和監(jiān)控面板中找出幾條慢sql并進(jìn)行優(yōu)化采章。
優(yōu)化步驟
總結(jié)了一下悯舟,大致步驟如下:
- 定位優(yōu)化對(duì)象的性能瓶頸抵怎;
- 明確優(yōu)化目標(biāo)反惕;
- 從explain入手分析姿染;
- 找到優(yōu)化方法悬赏;
找出慢sql
首先進(jìn)入druid監(jiān)控后臺(tái)舷嗡,查看一下這幾天的運(yùn)行日志后进萄,慢sql的大致情況中鼠,如圖:
從監(jiān)控后臺(tái)看到的數(shù)據(jù)只是一個(gè)粗略的統(tǒng)計(jì)援雇,是一個(gè)總覽記錄,想要看到詳細(xì)的執(zhí)行記錄及其中的慢sql統(tǒng)計(jì)可以通過(guò)日志文件蚕涤,這個(gè)功能也已經(jīng)整合到項(xiàng)目中揖铜,直接在tomcat的logs目錄即可查看天吓。
日志文件內(nèi)容節(jié)選:
//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]
日志的記錄格式為 [執(zhí)行時(shí)間] -慢sql執(zhí)行耗時(shí) 物邑,sql語(yǔ)句拂封,其實(shí)日志中記錄是挺多的,去重之后從日志文件中單獨(dú)選了幾條比較典型的sql語(yǔ)句進(jìn)行優(yōu)化钟病。
explain關(guān)鍵字
explain關(guān)鍵字一般放在SELECT查詢語(yǔ)句的前面肠阱,用于描述MySQL如何執(zhí)行查詢操作屹徘、以及MySQL成功返回結(jié)果集需要執(zhí)行的行數(shù)噪伊。explain 可以幫助我們分析 select 語(yǔ)句,讓我們知道查詢效率低下的原因,從而改進(jìn)我們查詢,讓查詢優(yōu)化器能夠更好的工作鉴吹。
用法:
結(jié)果集說(shuō)明如下:
項(xiàng) | 說(shuō)明 |
---|---|
id | MySQL Query Optimizer選定的執(zhí)行計(jì)劃中查詢的序列號(hào)豆励。表示查詢中執(zhí)行select子句或操作表的順序,id值越大優(yōu)先級(jí)越高,越先被執(zhí)行良蒸。id相同,執(zhí)行順序由上至下。 |
select_type 查詢類型 | 說(shuō)明 |
---|---|
SIMPLE | 簡(jiǎn)單的select查詢,不使用union及子查詢剿吻。 |
PRIMARY | 最外層的select查詢和橙。 |
UNION | UNION 中的第二個(gè)或隨后的 select查詢,不依賴于外部查詢的結(jié)果集魔招。 |
DEPENDENT UNION | UNION中的第二個(gè)或隨后的 select查詢,依 賴于外部查詢的結(jié)果集办斑。 |
SUBQUERY | 子查詢中的第一個(gè)select查詢,不依賴于外部查詢的結(jié)果集乡翅。 |
DEPENDENT SUBQUERY | 子查詢中的第一個(gè)select查詢,依賴于外部查詢的結(jié)果集蠕蚜。 |
DERIVED | 用于from子句里有子查詢的情況靶累。MySQL會(huì)遞歸執(zhí)行這些子查詢,把結(jié)果放在臨時(shí)表里挣柬。 |
UNCACHEABLE SUBQUERY | 結(jié)果集不能被緩存的子查詢,必須重新為外層查詢的每一行進(jìn)行評(píng)估邪蛔。 |
UNCACHEABLE UNION | UNION中的第二個(gè)或隨后的select查詢,屬于不可緩存的子查詢侧到。 |
項(xiàng) | 說(shuō)明 |
---|---|
table | 輸出行所引用的表 |
type 顯示連接使用的類型,按最優(yōu)到最差的類型排序 | 說(shuō)明 |
---|---|
system | 表僅有一行(=系統(tǒng)表)床牧。這是const連接類型的一個(gè)特例戈咳。 |
const | const用于用常數(shù)值比較PRIMARY KEY時(shí)删铃。當(dāng)查詢的表僅有一行時(shí),使用System猎唁。 |
eq_ref | const用于用常數(shù)值比較PRIMARY KEY時(shí)诫隅。當(dāng)查詢的表僅有一行時(shí),使用System逐纬。 |
ref | 連接不能基于關(guān)鍵字選擇單個(gè)行,可能查找到多個(gè)符合條件的行豁生。叫做ref是因?yàn)樗饕硞€(gè)參考值相比較甸箱。這個(gè)參考值或者是一個(gè)常數(shù),或者是來(lái)自一個(gè)表里的多表查詢的結(jié)果值 |
ref_or_null | 如同ref, 但是MySQL必須在初次查找的結(jié)果里找出null條目,然后進(jìn)行二次查找迅脐。 |
index_merge | 說(shuō)明索引合并優(yōu)化被使用了谴蔑。 |
unique_subquery | 在某些IN查詢中使用此種類型,而不是常規(guī)的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 | 只檢索給定范圍的行,使用一個(gè)索引來(lái)選擇行树碱。key列顯示使用了哪個(gè)索引成榜。當(dāng)使用=赎婚、<>樱溉、>福贞、>=、<恋技、<=逻族、IS NULL聘鳞、<=>抠璃、BETWEEN或者IN操作符,用常量比較關(guān)鍵字列時(shí),可以使用range。 |
index | 全表掃描,只是掃描表的時(shí)候按照索引次序進(jìn)行而不是行源请。主要優(yōu)點(diǎn)就是避免了排序,但是開銷仍然非常大谁尸。 |
all | 最壞的情況,從頭到尾全表掃描良蛮。 |
項(xiàng) | 說(shuō)明 |
---|---|
possible_keys | 指出MySQL能在該表中使用哪些索引有助于查詢决瞳。如果為空,說(shuō)明沒(méi)有可用的索引皮胡。 |
項(xiàng) | 說(shuō)明 |
---|---|
key | MySQL實(shí)際從possible_key選擇使用的索引屡贺。如果為NULL,則沒(méi)有使用索引甩栈。很少的情況下,MYSQL 會(huì)選擇優(yōu)化不足的索引量没。這種情況下,可以在SELECT語(yǔ)句中使用USE INDEX (indexname)來(lái)強(qiáng)制使用一個(gè)索引或者用IGNORE INDEX(indexname)來(lái)強(qiáng)制MYSQL忽略索引 |
項(xiàng) | 說(shuō)明 |
---|---|
key_len | 使用的索引的長(zhǎng)度殴蹄。在不損失精確性的情況下,長(zhǎng)度越短越好。 |
項(xiàng) | 說(shuō)明 |
---|---|
ref | 顯示索引的哪一列被使用了 |
項(xiàng) | 說(shuō)明 |
---|---|
rows | MYSQL認(rèn)為必須檢查的用來(lái)返回請(qǐng)求數(shù)據(jù)的行數(shù) |
extra 中出現(xiàn)以下2項(xiàng)意味著MYSQL根本不能使用索引,效率會(huì)受到重大影響漩蟆。應(yīng)盡可能對(duì)此進(jìn)行優(yōu)化怠李。
extra項(xiàng) | 說(shuō)明 |
---|---|
Using filesort | 表示MySQL會(huì)對(duì)結(jié)果使用一個(gè)外部索引排序,而不是從表里按索引次序讀到相關(guān)內(nèi)容捺癞∷杞椋可能在內(nèi)存或者磁盤上進(jìn)行排序唐础。MySQL中無(wú)法利用索引完成的排序操作稱為“文件排序” |
Using temporary | 表示MySQL在對(duì)查詢結(jié)果排序時(shí)使用臨時(shí)表矾飞。常見(jiàn)于排序order by和分組查詢 group by洒沦。 |
優(yōu)化目標(biāo)
優(yōu)化的目標(biāo)是一定要明確的申眼,不然根本無(wú)從下手括尸,針對(duì)于前文中提到的sql語(yǔ)句,及explain關(guān)鍵字的解釋钓辆,我列出了兩條目標(biāo):
- 避免全表掃描
- rows參數(shù)盡量減小
至于為什么只列出這兩條目標(biāo),主要是因?yàn)轫?xiàng)目中并沒(méi)有復(fù)雜的邏輯娶眷,也也沒(méi)有復(fù)雜的查詢届宠,建表時(shí)也并沒(méi)有根據(jù)相關(guān)查詢創(chuàng)建索引豌注,而且數(shù)據(jù)量也不大轧铁,因此能夠優(yōu)化的點(diǎn)并不是太多齿风,即使做了優(yōu)化也不能顯著的提升速度及性能救斑,因此就先列了兩個(gè)簡(jiǎn)單的小目標(biāo)穷娱,先體驗(yàn)一下explain關(guān)鍵字在sql優(yōu)化中的作用运沦。
優(yōu)化
針對(duì)第2條更新文章sql茶袒,執(zhí)行時(shí)間較長(zhǎng)的原因主要是因?yàn)閿?shù)據(jù)量太大薪寓,應(yīng)該是一個(gè)朋友在測(cè)試的時(shí)候做的操作向叉,article_content字段插入了一條20萬(wàn)字符大小的數(shù)據(jù),因此瘦黑,主要問(wèn)題在于插入數(shù)據(jù)過(guò)大奇唤,代碼已經(jīng)更新了參數(shù)檢查功能甲葬,在程序中做了限制经窖。
對(duì)于另外兩條查詢語(yǔ)句,首先用explain分析sql語(yǔ)句画侣,如下:
注意其中的兩個(gè)參數(shù)冰悠,type都是all,rows較小配乱,都為總記錄溉卓,我們的兩個(gè)目標(biāo)是什么?type不能為all宪卿,rows盡量小的诵,這里似乎滿足了一個(gè)條件,其實(shí)不然佑钾,因?yàn)檫@兩個(gè)表的數(shù)據(jù)量小西疤,因此rows值也小,如果換一張表(book表較大),以相同格式執(zhí)行一條sql得到如下結(jié)果:
rows為416孽尽,并沒(méi)有因?yàn)槭褂昧薼imit關(guān)鍵字而返回較小的值,因此兩條sql都需要做一下簡(jiǎn)單的優(yōu)化速勇。
幾張表都沒(méi)有創(chuàng)建索引都伪,是不是就沒(méi)有索引了呢磅轻?其實(shí)不然,你可能忽略了一點(diǎn),就是主鍵索引,索引的知識(shí)點(diǎn)在接下來(lái)一篇文章中會(huì)寫,這一篇就簡(jiǎn)單的提一下,因此優(yōu)化策略就是使用主鍵索引,將type由all變?yōu)閕ndex,稍微優(yōu)化了一點(diǎn)點(diǎn),改寫后的sql語(yǔ)句如下,分析結(jié)果如下:
通過(guò)與上面的結(jié)果對(duì)比损话,可以看到rows值也變小了。
type由all全部變?yōu)閕ndex齐佳。
總結(jié)
由于項(xiàng)目比較簡(jiǎn)單,都是操作單表的sql語(yǔ)句,沒(méi)有復(fù)雜查詢,也沒(méi)有多表的連接查詢,速度提升并沒(méi)有太多,對(duì)于目前的項(xiàng)目來(lái)說(shuō),不會(huì)有特別大的優(yōu)化動(dòng)作歹苦,如果以后有機(jī)會(huì)再去結(jié)合實(shí)際案例去優(yōu)化,現(xiàn)在就點(diǎn)到為止了,這一篇主要是介紹一下druid監(jiān)控的成果以及mysql查詢優(yōu)化的explain關(guān)鍵字悠砚,因此并沒(méi)有做太多的案例及分析,只是做了一些小修改别智,使得大家對(duì)explain關(guān)鍵字有了一些了解,下一篇會(huì)繼續(xù)做一些優(yōu)化改動(dòng)。