記一次程序優(yōu)化

入職一周吭练,還算比較清閑竞帽。沒(méi)有一些明確時(shí)間點(diǎn)的事情椿息,所以目前的大部分時(shí)候悠反,探索成分居多嗤军,絞盡腦汁做的某些架構(gòu)設(shè)計(jì)注盈,不談結(jié)果,就過(guò)程而言叙赚,收獲頗豐老客。
總的來(lái)說(shuō),蠻喜歡目前的狀態(tài)震叮,思考>編碼胧砰。
今天下午,旁邊的同事在做一個(gè)關(guān)于庫(kù)上的檢查苇瓣,簡(jiǎn)單說(shuō)就是判斷數(shù)據(jù)庫(kù)的某些字段是否唯一尉间。
最開(kāi)始是一條sql語(yǔ)句,大概是這樣的:

select * from aaa group by aaa.bbb, aaa.ccc having count(*) > 1;

全表大概1000w的數(shù)據(jù)击罪,第一次執(zhí)行哲嘲,用了16分鐘

我們的mysql是架在一臺(tái)12核媳禁,128Gb內(nèi)存的機(jī)器上眠副,應(yīng)該說(shuō)資源是足夠的,但是這樣的執(zhí)行時(shí)間竣稽,相比于oracle的2分鐘左右的處理速度囱怕,還是慢了太多。
單純select *大概在1分鐘左右毫别,所以大部分的開(kāi)銷在group by上娃弓,從這點(diǎn)上看,mysql的一些計(jì)算能力確實(shí)欠缺太多岛宦。

后來(lái)考慮優(yōu)化忘闻,將select *的結(jié)果全部裝入內(nèi)存,然后進(jìn)行查找恋博。
思路上齐佳,沒(méi)有任何問(wèn)題私恬,但他的實(shí)施是這樣的:
判斷重復(fù)時(shí),使用了2個(gè)循環(huán)炼吴,如下:

vector<string> data;

for (int i = 0; i < data.size(); i++)
{
    for (int j = i + 1; j < data.size(); j++)
    {
        if (data[i] == data[j])
        {
            //do some
        }
    }
}

這個(gè)代碼執(zhí)行了大概30分鐘本鸣,仍然沒(méi)有結(jié)果。
正好當(dāng)時(shí)沒(méi)事硅蹦,就幫他做了一些優(yōu)化荣德。很顯然,這樣的一個(gè)唯一性檢查使用窮舉是有問(wèn)題的童芹,復(fù)雜度在O(N^2)涮瞻,對(duì)于1000w這樣的數(shù)量級(jí),O(N^2)基本上是不可實(shí)現(xiàn)的假褪。所以第一步的優(yōu)化署咽,就是將這個(gè)算法的復(fù)雜度降下來(lái)。
增加一個(gè)排序操作生音,這樣宁否,程序的處理流程將變?yōu)椋?br> 1 排序
2 兩兩比較,確定非唯一值

總體的復(fù)雜度為O(N logN)
在排序中缀遍,使用了stl的sort函數(shù)進(jìn)行排序慕匠,程序整體執(zhí)行一遍的時(shí)間為7分鐘。刨掉出庫(kù)select的1分鐘域醇,排序的時(shí)間在6分鐘左右台谊。這么說(shuō)來(lái),還是有些慢譬挚。這個(gè)時(shí)候青伤,更好的優(yōu)化方式是將算法更改為hash,這樣時(shí)間復(fù)雜度將降為O(N)殴瘦,那么將會(huì)有質(zhì)的提升狠角,但是考慮到stl的map是紅黑樹(shù)實(shí)現(xiàn),復(fù)雜度為O(N logN)蚪腋,并不是很好的選擇丰歌,而自己重新寫(xiě)一個(gè)hash函數(shù)好像又比較麻煩。所以權(quán)衡了一下屉凯,還是繼續(xù)從排序入手立帖。

最開(kāi)始,想要將排序操作轉(zhuǎn)移到mysql上執(zhí)行悠砚,也就是在出庫(kù)的同時(shí)進(jìn)行排序晓勇,需要把出庫(kù)語(yǔ)句改為:

select * from aaa order by aaa.bbb, aaa.ccc;

這樣之后,內(nèi)存中只需要一次遍歷就好,時(shí)間開(kāi)銷基本可以忽略绑咱,這條sql的執(zhí)行時(shí)間為4分鐘绰筛,雖然相比于前面有了一些提升,但還是不夠理想描融,還需要進(jìn)一步的優(yōu)化铝噩。

在上文的程序中,我們發(fā)現(xiàn)全部的數(shù)據(jù)存儲(chǔ)在一個(gè)vector里窿克,每一條數(shù)據(jù)為一個(gè)string骏庸,因此核心的開(kāi)銷為string的operator < 比較操作。string是一個(gè)相對(duì)來(lái)說(shuō)比較龐大的類年叮,會(huì)造成許多的額外開(kāi)銷具被。
我們只需要比較2個(gè)字段的唯一性,完全可以將這兩個(gè)字段拼接起來(lái)只损,存在一個(gè)char*中一姿,之后的比較基于memcmp。
當(dāng)然改执,可能有這樣的問(wèn)題啸蜜,第一條記錄的第一個(gè)字段為“123”坑雅,第二個(gè)字段為“456”辈挂;而第二條記錄的第一個(gè)字段為“12”,第二個(gè)字段為“3456”裹粤,這樣本來(lái)不等的兩個(gè)字段终蒂,拼接后相同。解決方式也很簡(jiǎn)單遥诉,在“123”的結(jié)束位置加入一個(gè)特殊字符拇泣,再拼接,這樣就可以了矮锈。
在更改為char*之后霉翔,數(shù)據(jù)的排序時(shí)間從原來(lái)的3分鐘降到了40秒

目前來(lái)看苞笨,總體的執(zhí)行時(shí)間為1分鐘40秒债朵,其中出庫(kù)1分鐘,排序40秒瀑凝。系統(tǒng)的整體瓶頸轉(zhuǎn)移到了出庫(kù)這里序芦,這里的優(yōu)化方式就相當(dāng)明顯了,我們只是用到了2個(gè)字段粤咪,完全沒(méi)有必要select *谚中,只需要將select語(yǔ)句改為:

select aaa.bbb, aaa.ccc from aaa;

這樣更改后,出庫(kù)的時(shí)間為13秒,整體的執(zhí)行時(shí)間為50秒宪塔。

這個(gè)時(shí)間磁奖,已經(jīng)完全符合要求了,但是為了追求更高的速度蝌麸,繼續(xù)將計(jì)算并行化点寥,也就是說(shuō),充分利用cpu的多核計(jì)算能力来吩,將任務(wù)盡可能的拆分為多個(gè)線程來(lái)完成敢辩。對(duì)于本例來(lái)說(shuō),我們并不需要整體有序的數(shù)據(jù)弟疆,因此戚长,考慮hadoop的分桶思想,我們將取出的char*每位相加怠苔,得到的結(jié)果對(duì)10取余同廉,將結(jié)果分散到10個(gè)線程去做,最后的執(zhí)行結(jié)果為4秒鐘柑司。

經(jīng)過(guò)上面的一步步優(yōu)化迫肖,總共的執(zhí)行時(shí)間為17秒
(原文時(shí)間2014-1-15)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末攒驰,一起剝皮案震驚了整個(gè)濱河市蟆湖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌玻粪,老刑警劉巖隅津,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異劲室,居然都是意外死亡伦仍,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)很洋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)充蓝,“玉大人,你說(shuō)我怎么就攤上這事喉磁∥焦叮” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵线定,是天一觀的道長(zhǎng)娜谊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)斤讥,這世上最難降的妖魔是什么纱皆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任湾趾,我火速辦了婚禮,結(jié)果婚禮上派草,老公的妹妹穿的比我還像新娘搀缠。我一直安慰自己,他們只是感情好近迁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布艺普。 她就那樣靜靜地躺著,像睡著了一般鉴竭。 火紅的嫁衣襯著肌膚如雪歧譬。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天搏存,我揣著相機(jī)與錄音瑰步,去河邊找鬼。 笑死璧眠,一個(gè)胖子當(dāng)著我的面吹牛缩焦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播责静,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼袁滥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了灾螃?” 一聲冷哼從身側(cè)響起题翻,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎睦焕,沒(méi)想到半個(gè)月后藐握,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體靴拱,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垃喊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袜炕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片本谜。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖偎窘,靈堂內(nèi)的尸體忽然破棺而出乌助,到底是詐尸還是另有隱情,我是刑警寧澤陌知,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布他托,位于F島的核電站,受9級(jí)特大地震影響仆葡,放射性物質(zhì)發(fā)生泄漏赏参。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望把篓。 院中可真熱鬧纫溃,春花似錦、人聲如沸韧掩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)疗锐。三九已至坊谁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滑臊,已是汗流浹背呜袁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留简珠,地道東北人阶界。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像聋庵,于是被迫代替她去往敵國(guó)和親膘融。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

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

  • 場(chǎng)景: 生產(chǎn)上發(fā)薪在過(guò)賬時(shí)過(guò)長(zhǎng)祭玉,特別是發(fā)薪人數(shù)過(guò)多時(shí)氧映,耗時(shí)非常巨大,嚴(yán)重影響發(fā)薪效率脱货; 例如:廚房電器過(guò)賬人數(shù)1....
    小超_f598閱讀 635評(píng)論 0 0
  • 特別說(shuō)明: 1岛都、本文只是面對(duì)數(shù)據(jù)庫(kù)應(yīng)用開(kāi)發(fā)的程序員,不適合專業(yè)DBA振峻,DBA在數(shù)據(jù)庫(kù)性能優(yōu)化方面需要了解更多的知識(shí)...
    安易學(xué)車閱讀 1,821評(píng)論 0 40
  • SQL 優(yōu)化(載錄于:http://m.jb51.net/article/5051.htm) 作者: (一)深入淺...
    yuantao123434閱讀 734評(píng)論 0 7
  • 原文:https://my.oschina.net/liuyuantao/blog/751438 查詢集API 參...
    陽(yáng)光小鎮(zhèn)少爺閱讀 3,826評(píng)論 0 8
  • 風(fēng)雨人生 文/火樹(shù)銀花 風(fēng) 瘋夠了吧 回到家中息息腳吧 雨 淋透了吧 歸至港灣更更衣吧 人 混慘了...
    竹花閱讀 170評(píng)論 1 1