很高興迷雪!終于踩到了慢查詢的坑

之前看了餓了么團(tuán)隊(duì)寫的一篇博客:等等!這兩個(gè) Spring-RabbitMQ 的坑我們已經(jīng)替你踩了虫蝶。深受啟發(fā)章咧,一定要取個(gè)能吸引讀者眼球的標(biāo)題,當(dāng)然除了響當(dāng)當(dāng)?shù)臉?biāo)題以外能真,內(nèi)容也要是干貨赁严。為什么會(huì)想取這樣一個(gè)標(biāo)題,因?yàn)榭戳死碚撋系穆樵儍?yōu)化粉铐,今天L墼肌!蝙泼!終于在生產(chǎn)上實(shí)戰(zhàn)了

(一)慢sql一

問題發(fā)現(xiàn)

將應(yīng)用發(fā)布到生產(chǎn)環(huán)境后程剥,前端頁面請求后臺(tái)API返回?cái)?shù)據(jù),發(fā)現(xiàn)至少需要6s踱承。查看到慢sql:


慢sql定位.png

復(fù)現(xiàn)慢sql

執(zhí)行sql:

select count(*) from sync_block_data
where unix_timestamp(sync_dt) >= 1539101010
AND unix_timestamp(sync_dt) <= 1539705810

查看耗時(shí):


慢查詢耗時(shí).png

一共耗時(shí)為2658ms
查看執(zhí)行計(jì)劃:

explain select count(*) from sync_block_data
where unix_timestamp(sync_dt) >= 1539101010
AND unix_timestamp(sync_dt) <= 1539705810

執(zhí)行計(jì)劃結(jié)果:


慢查詢執(zhí)行計(jì)劃.png

優(yōu)化慢sql一

sync_dt的類型為datetime類型倡缠。換另外一種sql寫法哨免,直接通過比較日期而不是通過時(shí)間戳進(jìn)行比較茎活。將sql中的時(shí)間戳轉(zhuǎn)化為日期,分別為2018-10-10 00:03:30和2018-10-17 00:03:30
執(zhí)行sql:

select count(*) from sync_block_data
where sync_dt >= "2018-10-10 00:03:30"
AND sync_dt <= "2018-10-17 00:03:30"

查看耗時(shí):


快查詢耗時(shí).png

一共耗時(shí)419毫秒琢唾,和慢查詢相比速度提升六倍多
查看執(zhí)行計(jì)劃:

explain select count(*) from sync_block_data
where sync_dt >= "2018-10-10 00:03:30"
AND sync_dt <= "2018-10-17 00:03:30"

執(zhí)行計(jì)劃結(jié)果:


快查詢執(zhí)行計(jì)劃.png

訪問頁面载荔,優(yōu)化完成后請求時(shí)間平均為900毫秒


image.png

執(zhí)行計(jì)劃中慢查詢和快查詢唯一的區(qū)別就是type不一樣:慢查詢中type為index,快查詢中type為range采桃。

優(yōu)化慢查詢二

這條sql的業(yè)務(wù)邏輯為統(tǒng)計(jì)出最近七天該表的數(shù)據(jù)量懒熙,可以去掉右邊的小于等于
執(zhí)行sql:

select count(*) from sync_block_data
where sync_dt >= "2018-10-10 00:03:30"

查看耗時(shí):


image.png

一共耗時(shí)275毫秒,又將查詢時(shí)間減少了一半
查看執(zhí)行計(jì)劃:

explain select count(*) from sync_block_data
where sync_dt >= "2018-10-10 00:03:30"

執(zhí)行計(jì)劃結(jié)果:


image.png

type仍是range普办。但是通過少比較一次將查詢速度提高一倍

優(yōu)化慢查詢?nèi)?/h3>

新建一個(gè)bigint類型字段sync_dt_long存儲(chǔ)sync_dt的毫秒值工扎,并在sync_dt_long字段上建立索引
測試環(huán)境下:
優(yōu)化慢查詢二sql

select count(*) from copy_sync_block_data
where sync_dt >="2018-10-10 13:15:02"

耗時(shí)為34毫秒
優(yōu)化慢查詢?nèi)齭ql

select count(*) from copy_sync_block_data
where sync_dt_long >= 1539148502916

耗時(shí)為22毫秒
測試環(huán)境中速度提升10毫秒左右

優(yōu)化慢查詢?nèi)齭ql測試小結(jié):在InnoDB存儲(chǔ)引擎下,比較bigint的效率高于datetime
完成三步優(yōu)化以后生產(chǎn)環(huán)境中請求耗時(shí):


image.png

速度又快了200毫秒左右衔蹲。通過給查詢的數(shù)據(jù)加10s緩存肢娘,響應(yīng)速度最快平均為20s

explain使用介紹

通過explain,可以查看sql語句的執(zhí)行情況(比如查詢的表,使用的索引以及mysql在表中找到所需行的方式等)
用explain查詢mysql查詢計(jì)劃的輸出參數(shù)有:

列名 說明
id 執(zhí)行編號(hào)橱健,標(biāo)識(shí)select所屬的行而钞。如果在語句中沒子查詢或關(guān)聯(lián)查詢,只有唯一的select拘荡,每行都將顯示1臼节。否則,內(nèi)層的select語句一般會(huì)順序編號(hào)珊皿,對應(yīng)于其在原始語句中的位置
select_type 顯示本行是簡單或復(fù)雜select网缝。如果查詢有任何復(fù)雜的子查詢,則最外層標(biāo)記為PRIMARY(DERIVED蟋定、UNION途凫、UNION RESUlT)
table 訪問引用哪個(gè)表(引用某個(gè)查詢,如“derived3”)
type 數(shù)據(jù)訪問/讀取操作類型(ALL溢吻、index维费、range、ref促王、eq_ref犀盟、const/system、NULL)
possible_keys 揭示哪一些索引可能有利于高效的查找
key 顯示mysql決定采用哪個(gè)索引來優(yōu)化查詢
key_len 顯示mysql在索引里使用的字節(jié)數(shù)
ref 顯示了之前的表在key列記錄的索引中查找值所用的列或常量
rows 為了找到所需的行而需要讀取的行數(shù)蝇狼,估算值阅畴,不精確。通過把所有rows列值相乘迅耘,可粗略估算整個(gè)查詢會(huì)檢查的行數(shù)
Extra 額外信息贱枣,如using index、filesort等

重點(diǎn)關(guān)注type颤专,type類型的不同竟然導(dǎo)致性能差六倍EΩ纭!栖秕!


type顯示的是訪問類型春塌,是較為重要的一個(gè)指標(biāo),結(jié)果值從好到壞依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL 簇捍,一般來說只壳,得保證查詢至少達(dá)到range級(jí)別,最好能達(dá)到ref暑塑。

類型 說明
All 最壞的情況,全表掃描
index 和全表掃描一樣吼句。只是掃描表的時(shí)候按照索引次序進(jìn)行而不是行。主要優(yōu)點(diǎn)就是避免了排序, 但是開銷仍然非常大事格。如在Extra列看到Using index惕艳,說明正在使用覆蓋索引况毅,只掃描索引的數(shù)據(jù),它比按索引次序全表掃描的開銷要小很多
range 范圍掃描尔艇,一個(gè)有限制的索引掃描尔许。key 列顯示使用了哪個(gè)索引。當(dāng)使用=终娃、 <>味廊、>、>=棠耕、<余佛、<=、IS NULL窍荧、<=>辉巡、BETWEEN 或者 IN 操作符,用常量比較關(guān)鍵字列時(shí),可以使用 range
ref 一種索引訪問,它返回所有匹配某個(gè)單個(gè)值的行蕊退。此類索引訪問只有當(dāng)使用非唯一性索引或唯一性索引非唯一性前綴時(shí)才會(huì)發(fā)生郊楣。這個(gè)類型跟eq_ref不同的是,它用在關(guān)聯(lián)操作只使用了索引的最左前綴瓤荔,或者索引不是UNIQUE和PRIMARY KEY净蚤。ref可以用于使用=或<=>操作符的帶索引的列。
eq_ref 最多只返回一條符合條件的記錄输硝。使用唯一性索引或主鍵查找時(shí)會(huì)發(fā)生 (高效)
const 當(dāng)確定最多只會(huì)有一行匹配的時(shí)候今瀑,MySQL優(yōu)化器會(huì)在查詢前讀取它而且只讀取一次,因此非车惆眩快橘荠。當(dāng)主鍵放入where子句時(shí),mysql把這個(gè)查詢轉(zhuǎn)為一個(gè)常量(高效)
system 這是const連接類型的一種特例郎逃,表僅有一行滿足條件哥童。
Null 意味說mysql能在優(yōu)化階段分解查詢語句,在執(zhí)行階段甚至用不到訪問表或索引(高效)

出現(xiàn)慢查詢的原因

在where子句中使用了函數(shù)操作
出現(xiàn)慢查詢的sql語句中使用了unix_timestamp函數(shù)統(tǒng)計(jì)出自'1970-01-01 00:00:00'的到當(dāng)前時(shí)間的秒數(shù)差衣厘。導(dǎo)致索引全掃描統(tǒng)計(jì)出近七天的數(shù)據(jù)量的

解決方案

盡量避免在where子句中對字段進(jìn)行函數(shù)操作如蚜,這將導(dǎo)致存儲(chǔ)引擎放棄使用索引而進(jìn)行全表掃描压恒。對于需要計(jì)算的值最好通過程序計(jì)算好傳入而不是在sql語句中做計(jì)算影暴,比如這個(gè)sql中我們將當(dāng)前的日期和七天前的日期計(jì)算好傳入

后記

這個(gè)問題當(dāng)時(shí)在測試環(huán)境沒有發(fā)現(xiàn),測試環(huán)境的請求速度還是可以的探赫。沒有被發(fā)現(xiàn)可以歸結(jié)為數(shù)據(jù)量型宙。生產(chǎn)數(shù)據(jù)量為百萬級(jí)別,測試環(huán)境數(shù)據(jù)量為萬級(jí)伦吠,數(shù)據(jù)量差50倍妆兑,數(shù)據(jù)量的增大把慢查詢的問題也放大了魂拦。

(二)慢sql二

因?yàn)榫€上出現(xiàn)了很明顯的請求響應(yīng)慢的問題,又去看了項(xiàng)目中的其他sql搁嗓,發(fā)現(xiàn)還有sql執(zhí)行的效率比較低

復(fù)現(xiàn)慢sql

執(zhí)行sql

select FROM_UNIXTIME(copyright_apply_time/1000,'%Y-%m-%d') point,count(1) nums
from resource_info where copyright_apply_time >= 1539336488355 and copyright_apply_time <= 1539941288355 group by point

查看耗時(shí):


image.png

耗時(shí)為1123毫秒
查看執(zhí)行計(jì)劃:

explain select FROM_UNIXTIME(copyright_apply_time/1000,'%Y-%m-%d') point,count(1) nums
from resource_info where copyright_apply_time >= 1539336488355 and copyright_apply_time <= 1539941288355 group by point

執(zhí)行計(jì)劃結(jié)果:


image.png

索引是命中了芯勘,但是extra字段中出現(xiàn)了Using temporary和Using filesort

優(yōu)化慢sql一

group by實(shí)質(zhì)是先排序后分組,也就是分組之前必排序腺逛。通過分組的時(shí)候禁止排序優(yōu)化sql
執(zhí)行sql:

select FROM_UNIXTIME(copyright_apply_time/1000,'%Y-%m-%d') point,count(1) nums
from resource_info where copyright_apply_time >= 1539336488355 and copyright_apply_time <= 1539941288355 group by point order by null

查看耗時(shí):


image.png

一共耗時(shí)1068毫秒荷愕,提高100毫秒左右,效果并不是特別明顯
查看執(zhí)行計(jì)劃:


image.png

extra字段已經(jīng)沒有Using filesort了棍矛,filesort表示通過對返回?cái)?shù)據(jù)進(jìn)行排序安疗。所有不是通過索引直接返回排序結(jié)果的排序都是FileSort排序,說明優(yōu)化后通過索引直接返回排序結(jié)果
Using temporary依然存在够委,出現(xiàn)Using temporary表示查詢有使用臨時(shí)表, 一般出現(xiàn)于排序, 分組和多表join的情況, 查詢效率不高, 仍需要進(jìn)行優(yōu)化荐类,這里出現(xiàn)臨時(shí)表的原因是數(shù)據(jù)量過大使用了臨時(shí)表進(jìn)行分組運(yùn)算

優(yōu)化慢sql二

慢查詢的sql業(yè)務(wù)邏輯為根據(jù)時(shí)間段分類統(tǒng)計(jì)出條件范圍內(nèi)各個(gè)時(shí)間段的數(shù)量
比如給定的條件范圍為2018-10-20~2018-10-27的時(shí)間戳,這條sql就會(huì)統(tǒng)計(jì)出2018-10-20~2018-10-27每天的數(shù)據(jù)增量∽旅保現(xiàn)在優(yōu)化成一天一天查玉罐,分別查七次數(shù)據(jù),去掉分組操作

select FROM_UNIXTIME(copyright_apply_time/1000,'%Y-%m-%d') point,count(1) nums
from resource_info where copyright_apply_time >= 1539855067355 and copyright_apply_time <= 1539941467355 

查看耗時(shí):


image.png

耗時(shí)為38毫秒潘拨,即使查7次所用時(shí)間也比1123毫秒少
查看執(zhí)行計(jì)劃:


image.png

extra字段中和慢查詢的extra相比少了Using temporary和Using filesort厌小。完美

就這樣第一次經(jīng)歷了真正的慢查詢以及慢查詢優(yōu)化,終于理論和實(shí)踐相結(jié)合了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末战秋,一起剝皮案震驚了整個(gè)濱河市璧亚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脂信,老刑警劉巖癣蟋,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異狰闪,居然都是意外死亡疯搅,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門埋泵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來幔欧,“玉大人,你說我怎么就攤上這事丽声〗刚幔” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵雁社,是天一觀的道長浴井。 經(jīng)常有香客問我,道長霉撵,這世上最難降的妖魔是什么磺浙? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任洪囤,我火速辦了婚禮,結(jié)果婚禮上撕氧,老公的妹妹穿的比我還像新娘瘤缩。我一直安慰自己,他們只是感情好伦泥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布款咖。 她就那樣靜靜地躺著,像睡著了一般奄喂。 火紅的嫁衣襯著肌膚如雪铐殃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天跨新,我揣著相機(jī)與錄音富腊,去河邊找鬼。 笑死域帐,一個(gè)胖子當(dāng)著我的面吹牛赘被,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肖揣,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼民假,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了龙优?” 一聲冷哼從身側(cè)響起羊异,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎彤断,沒想到半個(gè)月后野舶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宰衙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年平道,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片供炼。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡一屋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出袋哼,到底是詐尸還是另有隱情冀墨,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布先嬉,位于F島的核電站轧苫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏疫蔓。R本人自食惡果不足惜含懊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望衅胀。 院中可真熱鬧岔乔,春花似錦、人聲如沸滚躯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掸掏。三九已至茁影,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丧凤,已是汗流浹背募闲。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愿待,地道東北人浩螺。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像仍侥,于是被迫代替她去往敵國和親要出。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Mysql概述 數(shù)據(jù)庫是一個(gè)易于訪問和修改的信息集合农渊。它允許使用事務(wù)來確保數(shù)據(jù)的安全性和一致性患蹂,并能快速處理百萬條...
    彥幀閱讀 13,674評(píng)論 10 461
  • 轉(zhuǎn) # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 9,723評(píng)論 0 44
  • 其實(shí)算不上復(fù)盤,因?yàn)檫@個(gè)月沒有什么成就感砸紊。也算是堅(jiān)持了幾件小事况脆,比如寶貝聽故事打卡超過100天,完成一次記賬挑戰(zhàn)賽...
    家有倆男寶閱讀 180評(píng)論 0 0
  • 今天語文課上老師默寫了批糟,八個(gè)字格了。田禾手火蟲山云耳。我這八個(gè)字都寫上來了徽鼎。但云和火兩個(gè)字盛末,筆畫占位不對。沒有按照老師...
    張佳藝閱讀 844評(píng)論 0 1