一次千萬量級數(shù)據(jù)優(yōu)化之旅

2013年中嗤瞎,畢業(yè)第三年,初入上海听系,入職某大型物流公司贝奇,開啟了一段成長之旅

入職第三個(gè)月,很焦灼跛锌,從一個(gè)小公司出來弃秆,原來天不怕地不怕,技術(shù)我就是老大髓帽,現(xiàn)在公司大了菠赚,感覺人人都是大牛,我只不過是混進(jìn)來的小老鼠郑藏。一段時(shí)間下來衡查,感覺總是慫著也不是辦法,怎么辦必盖?找活干,我們經(jīng)理倒是爽快拌牲,好硬一塊骨頭甩過來,那是完全超出自己能力范圍的一個(gè)東西歌粥,怎么說呢塌忽,就像,拳臺上的鄒市明突然聽到自己的對手是泰森失驶。土居。完全不是會不會被咬耳朵的問題,,擦耀,

怎么辦棉圈,不能慫啊,只能把千萬只羊駝關(guān)在心里眷蜓,讓他們自由奔跑分瘾,自己呢,默默的去解決問題吁系,不過說實(shí)話德召,碰到這種沒有一毛錢頭緒的問題,反而讓我很興奮垮抗,感覺腦細(xì)胞完全不受限制的恣意奔跑氏捞。。冒版。哎 哎 哎液茎,你左腦的細(xì)胞跑去腦干干嘛,辞嗡,捆等,,

冷靜下來续室,開始對問題分析栋烤。

業(yè)務(wù)需求:

一線部門,需要根據(jù)查詢條件挺狰,查詢出本部門不同級別用戶的數(shù)據(jù)情況明郭,多么簡單的一個(gè)需求,我看了下丰泊,無非是張幾5千萬級別的數(shù)據(jù)表查詢薯定,哼哼,瞳购。话侄。哼哼。学赛。年堆。哼哼。盏浇。

1.暴露問題变丧,用最蠢的辦法,把多個(gè)查詢語句一一寫出來绢掰,最復(fù)雜的一個(gè)sql500行左右锄贷,包含了各種子查詢译蒂,子查詢A統(tǒng)計(jì)表A,子查詢A嵌套子查詢B谊却,子查詢B統(tǒng)計(jì)查詢join表C,子查詢D分組嵌套子查詢C,DC查詢結(jié)果關(guān)聯(lián)子查詢B,子查詢A關(guān)聯(lián)表BED,得出查詢列F.....編不下去了哑芹,總之各種子查詢結(jié)果統(tǒng)計(jì)炎辨,分組,排序聪姿,時(shí)間的對比碴萧,

2.我在考慮要不要辭職,我的職業(yè)生涯可能就這么跪了末购,

3.冷靜一想破喻,不行我是要做DNA的男人

4.運(yùn)行各個(gè)查詢,保證整個(gè)查詢結(jié)果是和正確的盟榴,起碼保證了語句是可用的了

5.來來來曹质,我們用線上備份時(shí)間跑一下

6.開始!1秒擎场,2秒羽德,,迅办,宅静,125秒,我們?nèi)コ楦鶡熣酒郏f不定結(jié)果就出來了姨夹,

7.400秒,矾策,磷账,450秒,蝴韭,够颠,咱們再去抽一根把。榄鉴。履磨。

8.2058秒,兩盒煙抽完了庆尘。剃诅。。kill

9.explan 語句驶忌,一個(gè)索引都不走矛辕。笑跛。。怎么可能會走索引聊品,里面包含了group by飞蹂,時(shí)間函數(shù),加減運(yùn)算翻屈。陈哑。還有不知名的排序。伸眶。惊窖。而表中的索引寥寥。厘贼。

10.

:DBA 這個(gè)表 這個(gè)表 還有這個(gè)表要建索引

:你搖頭什么意思界酒?什么線上數(shù)據(jù)會受影響?不就是建幾十個(gè)索引么嘴秸、毁欣、、

:.把你領(lǐng)導(dǎo)叫過來

:.jim哥赁遗,我錯(cuò)了署辉,我態(tài)度不好,恩 下次不敢了岩四,好哭尝,每人一個(gè)七喜沒問題

11.TMD 加了幾個(gè)索引還是不靠譜啊

12 :DBA姐姐,這是怎么回事剖煌?

:.索引不生效材鹦?索引覆蓋數(shù)據(jù)太多的話,引擎會認(rèn)為全表比較靠譜耕姊?什么鬼邏輯桶唐,hit一下

:.數(shù)據(jù)庫卡死了?我錯(cuò)了茉兰,kill掉吧

第一階段結(jié)束:數(shù)據(jù)量多大尤泽,查詢邏輯復(fù)雜,導(dǎo)致建立的索引很多時(shí)候是失效的规脸,而且索引建立過多坯约,線上數(shù)據(jù)在新增和修改,會受到很大的影響莫鸭,在數(shù)據(jù)變更的過程中闹丐,不僅是對數(shù)據(jù)操作,相關(guān)的索引文件也有進(jìn)行變動被因,導(dǎo)致操作性能低下

也開始意識到卿拴,這種數(shù)據(jù)量下衫仑,復(fù)雜的數(shù)據(jù)查詢邏輯下,全靠索引解決不了一毛錢問題

不得不召喚我的腦干細(xì)胞堕花,來解決問題

不如就從表結(jié)構(gòu)入手吧文狱,既然數(shù)據(jù)量太大,那就分表怎么樣

13 :.DBA姐姐航徙,我想到一個(gè)好辦法如贷,你覺得分表怎么樣

:分表?你咋不上天到踏?

:我剛從天上下來

:分手可以 分表不行

:為什么?

:因?yàn)槟闾珟浟俗逭梗覀儾缓线m

:我問你為啥分表不行?

:分表的話访忿,涉及到分表的規(guī)則凿掂,路由規(guī)則伴榔,另外你們之前寫的所有數(shù)據(jù)操作的邏輯都要重新寫,你問你們領(lǐng)導(dǎo)見

:不用問我們領(lǐng)導(dǎo)庄萎,這個(gè)事情我拍板踪少?

:?糠涛?援奢?

:不分就不分 有啥大不了

:分區(qū)總行吧

:分區(qū)可以

:那就分區(qū)吧

:回去把規(guī)則定了,看下查詢有沒有效果

14,:進(jìn)入到分區(qū)探索階段忍捡,問題:這么多張表集漾,按照什么進(jìn)行分區(qū)?那些表要分區(qū)砸脊?分區(qū)后sql語句如何調(diào)整

15:解決查詢問題:抽象一點(diǎn)來說具篇,每個(gè)查詢語句無論多復(fù)雜,包含三部分內(nèi)容:

一凌埂,結(jié)果集的行數(shù)(不考慮分頁驱显,當(dāng)未分頁的查詢速度提升了,分頁查詢更加快速)瞳抓,

二埃疫,結(jié)果集的列數(shù)(表字段或聚合函數(shù)),三挨下,排序分組

行數(shù)基本是有where條件決定的熔恢,盡量讓決定行數(shù)的sql效率最優(yōu),減少此sql不必要的聚合排序操作臭笆,就讓他安安靜靜的做行數(shù)查詢(A)叙淌,這部分只查詢需要的列秤掌,不要貪多哦,以此查詢的結(jié)果集為基礎(chǔ)鹰霍,再與其他表或子查詢進(jìn)行關(guān)聯(lián)查詢(標(biāo)注1)闻鉴,去達(dá)到結(jié)果集列數(shù)的要求,最后對結(jié)果進(jìn)行統(tǒng)一的分組排序聚合茂洒,這是我對于sql優(yōu)化最主要的幾個(gè)心得:

其中有幾個(gè)地方需要注意的孟岛,sql索引建立:

最常用的:單列索引,組合索引督勺,函數(shù)索引

添加索引依據(jù):where條件中的覆蓋度渠羞,索引的可選擇度

如果在大多數(shù)的查詢中會使用到某表某列的情況,建議添加索引智哀,但是在執(zhí)行sql的時(shí)候不一定會索引次询,在oracle中,大部分情況查詢結(jié)果超過全表的一定比例(10-15%)就不會走索引了瓷叫,屯吊,,尤其是幾千萬的表數(shù)據(jù)的情況

再說索引的可選擇度摹菠,當(dāng)一個(gè)列在標(biāo)準(zhǔn)重復(fù)度越低盒卸,表示此列作為索引的可選擇就越高,此列作為條件做=查詢時(shí)次氨,效率會更好蔽介,為什么?請參考唯一索引糟需。屉佳。。洲押。

16:回到正題武花,分區(qū)情況下,選擇了主表(基本靠這個(gè)表來過濾結(jié)果集行數(shù))中覆蓋度最高的字段作為分區(qū)字段杈帐,進(jìn)行比較常規(guī)的range分區(qū)体箕,就是按照這個(gè)字段的從小到大,分成1000個(gè)區(qū)間挑童,每個(gè)區(qū)間為一個(gè)分區(qū)表累铅,其他幾張表中,存在這個(gè)字段則進(jìn)行分區(qū)站叼,否則暫時(shí)不分區(qū)娃兽,明確下整個(gè)查詢中使用率最高的兩個(gè)字段一個(gè)是部門id字段,一個(gè)是用戶id尽楔,部門字段為分區(qū)字段投储,用戶id字段作為非分區(qū)表的主要關(guān)聯(lián)字段第练,這樣問題就變成了,在一個(gè)分區(qū)表中的結(jié)果集與其他表或者分區(qū)表的聯(lián)合查詢玛荞,速度果然馬上上來娇掏,起碼一根煙的時(shí)間可以看到結(jié)果,平均在10秒勋眯,

17:已經(jīng)有很大進(jìn)展婴梧,感覺看到了希望,接下來就是怎么把查詢更進(jìn)一步客蹋,再說明下問題塞蹭,部門字段是有層級關(guān)系的,如果單純查詢指定的部門其實(shí)問題不大在2,3秒是可以的讶坯,但是如果去查詢這個(gè)部門的下屬部門然后進(jìn)行統(tǒng)計(jì)浮还,查詢效率直線下降,怎么辦闽巩,?

18:離線計(jì)算担汤,先通過之前準(zhǔn)備的各個(gè)sql生成的結(jié)果存儲在各個(gè)表中(表分區(qū))涎跨,在接受查詢時(shí),不再通過各個(gè)sql實(shí)時(shí)計(jì)算而是去拿這些表中的數(shù)據(jù)崭歧,減少了很多不復(fù)雜的計(jì)算過程(聚合隅很,排序,函數(shù))率碾,然后用結(jié)果集去關(guān)聯(lián)一些表拉取需要的列數(shù)據(jù)叔营,這個(gè)離線表會每天進(jìn)行一次更新,只對有變更的用戶數(shù)據(jù)進(jìn)行所宰,只掃描前一天更新數(shù)據(jù)绒尊,屬于T_1的增量更新辦法

怎么更新?存儲過程啊仔粥,婴谱,千把行的存儲過程,每天更新一次躯泰,不知道現(xiàn)在維護(hù)這個(gè)代碼的同學(xué)是否還健在谭羔。我也來解釋下為什么要少用存儲過程,其實(shí)存儲過程對于數(shù)據(jù)操作性能很高麦向,畢竟是本地操作瘟裸,但是plsql本是也是種語言,要定義產(chǎn)量诵竭,要定義游標(biāo)话告,要關(guān)閉游標(biāo)兼搏,要做異常處理,要記錄錯(cuò)誤日志超棺,對于開發(fā)人員整體的代碼編寫和維護(hù)成本還是很高的向族,畢竟不是隨便拉一個(gè)人過來就可以噼里啪啦寫存儲過程的,這也導(dǎo)致了儲過程對程序員而言棠绘,可讀性很差導(dǎo)致做完這個(gè)需求后件相,我有段時(shí)間在回憶怎么寫java,,

完成這一步以后,基本已經(jīng)完成了一半氧苍,還要再找更憂的方式比如說部分離線計(jì)算的表(運(yùn)算量比較大)夜矗,換成物化視圖(區(qū)別于視圖),因?yàn)槲锘晥D支持自動更新(采用定時(shí)刷新)让虐,減少了存儲過程的維護(hù)量,而且物化視圖也支持索引紊撕,分區(qū)

1:8:還有什么問題?那就是線上數(shù)據(jù)的重定義

新需求上線時(shí)要保證之前需要分區(qū)的表把分區(qū)做好赡突,但是又不能影響線上的環(huán)境对扶,這個(gè)時(shí)候Oracle強(qiáng)大的地方就要體現(xiàn)了,在線重定義惭缰,mysql可沒有浪南,

此需求在線重定義的過程,其實(shí)就是將需要重定義的表進(jìn)行備份漱受,然后將備份表進(jìn)行分區(qū)络凿,分區(qū)完成后,重建索引(原有全局索引)昂羡,將備份表重命名為線上表名絮记,然后就沒有然后了,

細(xì)心的同學(xué)肯定會跳出來虐先,有bug怨愤,在重定位期間的,線上是有數(shù)據(jù)更新的赴穗,但是備份表拿不到這些數(shù)據(jù)憔四,這就是Oracle在線重定義的奧妙,數(shù)據(jù)的同步般眉,

如果換成mysql應(yīng)該怎么玩了赵?備份表,查詢當(dāng)前最大manxid甸赃,對備份表進(jìn)行分區(qū)操作柿汛,將原表中 id>maxId 的行復(fù)制到備份表,將原表重命名,然后備份表重命名络断,重命名階段會有短時(shí)間的間隔裁替,會有部分業(yè)務(wù)失敗,如果mysql現(xiàn)在又更高級的功能支持這個(gè)操作的貌笨,請指正

基本上這整個(gè)優(yōu)化以及完成弱判,在回頭看下結(jié)果,

首先對于部分表進(jìn)行分區(qū)锥惋,選擇那些表昌腰,當(dāng)時(shí)使用的原則是影響行數(shù)結(jié)果的表,查詢條件中使用最頻繁列膀跌,那些表分區(qū)遭商?包含這個(gè)列的都可以進(jìn)行分區(qū),具體看業(yè)務(wù)捅伤,建立合適的分區(qū)索引

2.對于未分區(qū)的表劫流,建立合適的索引:組合索引? 函數(shù)索引

3.對于計(jì)算復(fù)雜部分進(jìn)行離線運(yùn)算,提前將查詢結(jié)果集中存放在表中或物化視圖丛忆,建立分區(qū)祠汇,分區(qū)索引

4.維護(hù)工作,存儲過程熄诡,在線重定義座哩,

5.各個(gè)分區(qū)表的后續(xù)維護(hù),因?yàn)閿?shù)據(jù)時(shí)不斷增長的粮彤,分區(qū)列的數(shù)據(jù)也在增長,定時(shí)的進(jìn)行分區(qū)表的重新分區(qū)(或在建立分區(qū)時(shí)姜骡,將分區(qū)范圍放大导坟,比如目前分區(qū)列數(shù)據(jù)只有1-1000,分十個(gè)區(qū)圈澈,提取假想目前分區(qū)列數(shù)據(jù)時(shí)1-10000惫周,分一百個(gè)區(qū),保證未來一段時(shí)間康栈,不需要重新分區(qū)操作)

根據(jù)這個(gè)結(jié)果递递,在未分頁情況下,查詢性能基本在1秒以內(nèi)啥么,經(jīng)過壓測登舞,各個(gè)場景在200次請求/S的并發(fā)下,也是在1.1秒內(nèi)悬荣,也是未分區(qū)情況菠秒,功能上線后,分頁情況下基本都是0.5左右氯迂,算是一個(gè)合格的交付

疑問解答践叠,群里很多伙伴言缤,提到緩存的方式,將查詢結(jié)果緩存起來禁灼,這個(gè)方案基本上不可行的管挟,查詢條件是多變的,結(jié)果是隨時(shí)變的弄捕,不太適合這個(gè)場景

復(fù)盤:

· 這是四年前 能拿出來最好的方案僻孝,現(xiàn)在看來總體思路是可以的,但是不夠fashion

如果是我現(xiàn)在要怎么做察藐?

大體思路皮璧,依然對需要的表進(jìn)行分區(qū),統(tǒng)計(jì)結(jié)果集放在不同表中分飞,直接供查詢使用悴务,但是會放棄物化試圖和存儲過程,物化試圖沒有實(shí)質(zhì)性的提升譬猫,存儲過程成本太高不可控讯檐,總不能線上debug存儲過程,雖然oracle支持類似操作染服。離線更新方式用實(shí)時(shí)計(jì)算方式代替别洪,無論是采用流時(shí)計(jì)算還是看上去像流式計(jì)算,總有辦法達(dá)到目的柳刮,對統(tǒng)計(jì)的結(jié)果集表采用分表的方式挖垛,這些完成后,此類查詢可以獨(dú)立為一個(gè)服務(wù)秉颗,完全脫離了原有系統(tǒng)痢毒,無論從數(shù)據(jù)庫層還是代碼層面,可以獨(dú)立部署發(fā)布蚕甥,不會有后遺癥哪替,

缺點(diǎn)就是,相比之前的方式開發(fā)量更多菇怀,測試成本高凭舶,引入了諸多新功能風(fēng)險(xiǎn)也增加了,實(shí)時(shí)計(jì)算的冪等處理爱沟,數(shù)據(jù)丟失補(bǔ)償?shù)人蝗绱鎯^程高效直接,增加分表呼伸,表路由等問題

優(yōu)勢义屏,摒棄存儲過程將數(shù)據(jù)計(jì)算放入代碼中,可讀性高,采用分表的方式在實(shí)時(shí)計(jì)算方面闽铐,吞吐量也會上升蝶怔,統(tǒng)計(jì)過程更加平穩(wěn),完全脫離原系統(tǒng)兄墅,不存在耦合問題

具體可以參考下圖

歡迎大家加微信騷擾:treenpool

請持續(xù)關(guān)注踢星,http://treenpool.com國內(nèi)第一款專注于知識體系搭建工具

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市隙咸,隨后出現(xiàn)的幾起案子沐悦,更是在濱河造成了極大的恐慌,老刑警劉巖五督,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藏否,死亡現(xiàn)場離奇詭異,居然都是意外死亡充包,警方通過查閱死者的電腦和手機(jī)副签,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來基矮,“玉大人淆储,你說我怎么就攤上這事〖医剑” “怎么了本砰?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長钢悲。 經(jīng)常有香客問我点额,道長,這世上最難降的妖魔是什么莺琳? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任咖楣,我火速辦了婚禮,結(jié)果婚禮上芦昔,老公的妹妹穿的比我還像新娘。我一直安慰自己娃肿,他們只是感情好咕缎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著料扰,像睡著了一般凭豪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晒杈,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天嫂伞,我揣著相機(jī)與錄音,去河邊找鬼。 笑死帖努,一個(gè)胖子當(dāng)著我的面吹牛撰豺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拼余,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼污桦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了匙监?” 一聲冷哼從身側(cè)響起凡橱,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎亭姥,沒想到半個(gè)月后稼钩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡达罗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年坝撑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氮块。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绍载,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滔蝉,到底是詐尸還是另有隱情击儡,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布蝠引,位于F島的核電站阳谍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏螃概。R本人自食惡果不足惜矫夯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吊洼。 院中可真熱鬧训貌,春花似錦、人聲如沸冒窍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽综液。三九已至款慨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谬莹,已是汗流浹背檩奠。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工桩了, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人埠戳。 一個(gè)月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓井誉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親乞而。 傳聞我的和親對象是個(gè)殘疾皇子送悔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355

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

  • ORA-00001: 違反唯一約束條件 (.) 錯(cuò)誤說明:當(dāng)在唯一索引所對應(yīng)的列上鍵入重復(fù)值時(shí),會觸發(fā)此異常爪模。 O...
    我想起個(gè)好名字閱讀 5,317評論 0 9
  • 轉(zhuǎn) # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 9,728評論 0 44
  • 一欠啤、MySQL優(yōu)化 MySQL優(yōu)化從哪些方面入手: (1)存儲層(數(shù)據(jù)) 構(gòu)建良好的數(shù)據(jù)結(jié)構(gòu)∥莨啵可以大大的提升我們S...
    寵辱不驚丶?xì)q月靜好閱讀 2,433評論 1 8
  • 今天看到一位朋友寫的mysql筆記總結(jié)洁段,覺得寫的很詳細(xì)很用心,這里轉(zhuǎn)載一下共郭,供大家參考下祠丝,也希望大家能關(guān)注他原文地...
    信仰與初衷閱讀 4,734評論 0 30
  • 1 朋友就是拿來麻煩的,使“朋友”一詞有了更多的意義除嘹。我經(jīng)承窗耄“麻煩”朋友,也喜歡朋友來“麻煩”我尉咕,在被朋友“麻煩”...
    清酒無歡閱讀 404評論 0 0