MySQL在大數(shù)據(jù)肌似、高并發(fā)場景下的SQL語句優(yōu)化和"最佳實(shí)踐"2018-04-17

本文主要針對中小型應(yīng)用或網(wǎng)站蟆盹,重點(diǎn)探討日常程序開發(fā)中SQL語句的優(yōu)化問題匾寝,所謂“大數(shù)據(jù)”美澳、“高并發(fā)”僅針對中小型應(yīng)用而言懦鼠,專業(yè)的數(shù)據(jù)庫運(yùn)維大神請無視谍珊。以下實(shí)踐為個(gè)人在實(shí)際開發(fā)工作中滓彰,針對相對“大數(shù)據(jù)”和相對“高并發(fā)”場景的一些應(yīng)對策略稳捆,部分措施并沒有經(jīng)過嚴(yán)格的對比測試和原理分析嗤无,如有錯(cuò)漏歡迎各種批評指教猴贰。

減少查詢的影響結(jié)果集对雪,避免出現(xiàn)全表掃描。

影響結(jié)果集是SQL優(yōu)化的核心米绕。影響結(jié)果集不是查詢返回的記錄數(shù)瑟捣,而是查詢所掃描的結(jié)果數(shù)。通過Explain或Desc分析SQL栅干,rows列的值即為影響結(jié)果集(還可以通過慢查詢?nèi)罩镜腞ows_examined后面的數(shù)字得到)迈套。

以下是我常用的一些SQL優(yōu)化策略:

去掉不必要的查詢和搜索。其實(shí)在項(xiàng)目的實(shí)際應(yīng)用中碱鳞,很多查詢條件是可有可無的桑李,能從源頭上避免的多余功能盡量砍掉,這是最簡單粗暴的解決方案。

合理使用索引和復(fù)合索引贵白。建索引是SQL優(yōu)化中最有效的手段率拒。查找猬膨、刪除勃痴、更新以及排序時(shí)常用的字段可以適當(dāng)建立索引。不過要注意磷蜀,單條查詢不能同時(shí)使用多個(gè)索引召耘,只能使用一個(gè)索引。查詢條件較多時(shí)褐隆,可以使用多個(gè)字段合并的復(fù)合索引污它。切記,使用復(fù)合索引時(shí)庶弃,查詢條件的字段順序需要與復(fù)合索引的字段順序保持一致衫贬。

謹(jǐn)慎使用not

in等可能無法使用索引的條件。索引也不是什么時(shí)候都可以發(fā)揮作用的,當(dāng)出現(xiàn)"not in"缴守,"!="葬毫,"like

'%xx%'","is

null"等條件時(shí)屡穗,索引是無效的贴捡。使用這些條件的時(shí)候烂斋,請放到能有效使用索引的條件的右邊础废。設(shè)計(jì)表結(jié)構(gòu)時(shí)汛骂,個(gè)人建議盡可能用int類型代替varchar類型,int類型部分時(shí)候可以通過大于或小于代替"!="等條件评腺,同時(shí)也方便滿足一些需要按類型排序的需求帘瞭,至于可讀性的問題,完善好數(shù)據(jù)庫設(shè)計(jì)文檔才是明智的選擇蒿讥。同時(shí)建議把所有可能的字段設(shè)置為"not

null"图张,并設(shè)置默認(rèn)值锋拖,避免在where字句中出現(xiàn)"is null"的判斷。

不要在where子句中的“=”左邊進(jìn)行函數(shù)祸轮、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算,否則系統(tǒng)將無法正確使用索引侥钳。盡可能少用MySQL的函數(shù)适袜,類似Now()完全可以通過程序?qū)崿F(xiàn)并賦值,部分函數(shù)也可以通過適當(dāng)?shù)慕⑷哂嘧侄蝸黹g接替代舷夺。

在where條件中使用or苦酱,可能導(dǎo)致索引無效「可用 "union all" 或者 "union" (會(huì)過濾重復(fù)數(shù)據(jù)疫萤,效率比前者低) 代替,或程序上直接分開兩次獲取數(shù)據(jù)再合并敢伸,確保索引的有效利用扯饶。

不使用select * ,倒不是能提高查詢效率池颈,主要是減少輸出的數(shù)據(jù)量尾序,提高傳輸速度。

避免類型轉(zhuǎn)換躯砰,這里所說的“類型轉(zhuǎn)換”是指where子句中出現(xiàn)字段的類型和傳入的參數(shù)類型不一致的時(shí)候發(fā)生的類型轉(zhuǎn)換每币。

分頁查詢的優(yōu)化。頁數(shù)比較多的情況下琢歇,如limit 10000,10

影響的結(jié)果集是10010行兰怠,查詢速度會(huì)比較慢。推薦的解決方案是:先只查詢主鍵select id from table where ..

order by .. limit 10000,10(搜索條件和排序請建立索引)李茫,再通過主鍵去獲取數(shù)據(jù)揭保。

統(tǒng)計(jì)相關(guān)的查詢。影響結(jié)果集往往巨大涌矢,且部分SQL語句本身已經(jīng)難以優(yōu)化掖举。因此,應(yīng)避免在業(yè)務(wù)高峰期執(zhí)行統(tǒng)計(jì)相關(guān)的查詢娜庇,或者僅在從庫中執(zhí)行統(tǒng)計(jì)查詢塔次。部分統(tǒng)計(jì)數(shù)據(jù),可以通過冗余的數(shù)據(jù)結(jié)構(gòu)保存名秀,同時(shí)建議把數(shù)據(jù)先保存在內(nèi)存励负、緩存中(如redis),再按一定策略寫入數(shù)據(jù)庫匕得。

不使用任何連表查詢继榆,通過分庫和分表實(shí)現(xiàn)負(fù)載均衡巾表。

隨著數(shù)據(jù)量的增加,連表操作往往會(huì)導(dǎo)致影響結(jié)果集大增略吨,從SQL優(yōu)化的層面已經(jīng)解決不了問題了集币。

此時(shí),分庫和分表是解決數(shù)據(jù)庫性能壓力的最優(yōu)選擇(具體分庫和分表的方案通常結(jié)合實(shí)際業(yè)務(wù)的應(yīng)用場景來確定翠忠,此處略過)鞠苟。這里重點(diǎn)談,如何更好的實(shí)現(xiàn)或者過渡到分庫秽之、分表的分布式數(shù)據(jù)庫架構(gòu)当娱。

核心點(diǎn)就是必須先去除數(shù)據(jù)表之間的關(guān)聯(lián),即不用外鍵考榨,不使用任何連表查詢跨细。為了確保不進(jìn)行連表操作,在設(shè)計(jì)數(shù)據(jù)庫表結(jié)構(gòu)的時(shí)候河质,就需要設(shè)計(jì)適度冗余的字段來達(dá)到不連表的目的冀惭。

對于一些操作日志、支付記錄等愤诱,設(shè)計(jì)一些記錄用戶信息的字段云头,個(gè)人認(rèn)為其實(shí)不能算冗余,畢竟用戶信息往往會(huì)更改淫半,但是這種類似操作日志的表確實(shí)是需要記錄用戶操作時(shí)的信息溃槐,并且不需要在用戶更新信息時(shí)同步更新。

實(shí)際開發(fā)中科吭,為了實(shí)現(xiàn)不進(jìn)行連表而冗余的字段昏滴,往往是需要在原表更新數(shù)據(jù)的時(shí)候同步更新冗余字段的數(shù)據(jù)的,如果應(yīng)用層沒有對數(shù)據(jù)表操作做合理封裝对人,這往往是個(gè)棘手的問題谣殊,也不方便維護(hù)。

當(dāng)然牺弄,現(xiàn)在主流的應(yīng)用框架姻几,一般采用orm的方式處理數(shù)據(jù)表,所以問題不大势告。相反蛇捌,不連表事實(shí)上還可以提高開發(fā)效率,比如通過用戶ID獲取用戶姓名操作咱台,如果不連表就可以確保各個(gè)業(yè)務(wù)模塊都通過同樣的方式去獲取用戶姓名络拌,調(diào)用同一個(gè)封裝好的方法,這樣回溺,就能很方便的統(tǒng)一在應(yīng)用層加入緩存機(jī)制或添加統(tǒng)一的業(yè)務(wù)邏輯春贸。

同時(shí)如果要對用戶表進(jìn)行分庫分表混萝,通過應(yīng)用層程序就可以簡單平滑的實(shí)現(xiàn)。

使用Innodb萍恕。

關(guān)于Innodb和Myisam對比逸嘀,我就不多說了。Myisam的表級鎖是致命問題允粤,考慮到MySQL已經(jīng)默認(rèn)使用Innodb作為數(shù)據(jù)庫引擎厘熟,個(gè)人建議大部分情況可以直接使用Innodb,其他引擎這里就不詳細(xì)討論了维哈。這里有交流學(xué)習(xí)群:744642380里面會(huì)分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,MyBatis登澜,Netty源碼分析阔挠,高并發(fā)、高性能脑蠕、分布式购撼、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化這些成為架構(gòu)師必備的知識體系谴仙。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源迂求,目前受益良多

使用緩存。

1) 盡可能在程序上實(shí)現(xiàn)常用數(shù)據(jù)的緩存晃跺,目前主流的應(yīng)用框架應(yīng)該都能快速實(shí)現(xiàn)緩存的需求揩局。如果在程序上沒有實(shí)現(xiàn)數(shù)據(jù)緩存,開啟數(shù)據(jù)庫的query cache也是緩解數(shù)據(jù)庫壓力的方式之一掀虎,如果確認(rèn)使用凌盯,記得定時(shí)清理碎片flush query cache。

服務(wù)器相關(guān)優(yōu)化

MySQL服務(wù)配置以及分布式架構(gòu)的實(shí)現(xiàn)烹玉,請根據(jù)實(shí)際應(yīng)用場景和業(yè)務(wù)需求定制驰怎,非本文重點(diǎn),不做深入探討二打。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末县忌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子继效,更是在濱河造成了極大的恐慌症杏,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件莲趣,死亡現(xiàn)場離奇詭異鸳慈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)喧伞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門走芋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绩郎,“玉大人,你說我怎么就攤上這事翁逞±哒龋” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵挖函,是天一觀的道長状植。 經(jīng)常有香客問我,道長怨喘,這世上最難降的妖魔是什么津畸? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮必怜,結(jié)果婚禮上肉拓,老公的妹妹穿的比我還像新娘。我一直安慰自己梳庆,他們只是感情好暖途,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著膏执,像睡著了一般驻售。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上更米,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天欺栗,我揣著相機(jī)與錄音,去河邊找鬼壳快。 笑死纸巷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的眶痰。 我是一名探鬼主播瘤旨,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼竖伯!你這毒婦竟也來了存哲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤七婴,失蹤者是張志新(化名)和其女友劉穎祟偷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體打厘,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡修肠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了户盯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嵌施。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饲化,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吗伤,到底是詐尸還是另有隱情吃靠,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布足淆,位于F島的核電站巢块,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏巧号。R本人自食惡果不足惜族奢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望丹鸿。 院中可真熱鬧歹鱼,春花似錦、人聲如沸卜高。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掺涛。三九已至,卻和暖如春疼进,著一層夾襖步出監(jiān)牢的瞬間薪缆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工伞广, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拣帽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓嚼锄,卻偏偏與公主長得像减拭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子区丑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

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