記一次程序優化

入職一周,還算比較清閑。沒有一些明確時間點的事情,所以目前的大部分時候,探索成分居多,絞盡腦汁做的某些架構設計,不談結果,就過程而言,收獲頗豐。
總的來說,蠻喜歡目前的狀態,思考>編碼。
今天下午,旁邊的同事在做一個關于庫上的檢查,簡單說就是判斷數據庫的某些字段是否唯一。
最開始是一條sql語句,大概是這樣的:

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

全表大概1000w的數據,第一次執行,用了16分鐘

我們的mysql是架在一臺12核,128Gb內存的機器上,應該說資源是足夠的,但是這樣的執行時間,相比于oracle的2分鐘左右的處理速度,還是慢了太多。
單純select *大概在1分鐘左右,所以大部分的開銷在group by上,從這點上看,mysql的一些計算能力確實欠缺太多。

后來考慮優化,將select *的結果全部裝入內存,然后進行查找。
思路上,沒有任何問題,但他的實施是這樣的:
判斷重復時,使用了2個循環,如下:

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
        }
    }
}

這個代碼執行了大概30分鐘,仍然沒有結果。
正好當時沒事,就幫他做了一些優化。很顯然,這樣的一個唯一性檢查使用窮舉是有問題的,復雜度在O(N^2),對于1000w這樣的數量級,O(N^2)基本上是不可實現的。所以第一步的優化,就是將這個算法的復雜度降下來。
增加一個排序操作,這樣,程序的處理流程將變為:
1 排序
2 兩兩比較,確定非唯一值

總體的復雜度為O(N logN)
在排序中,使用了stl的sort函數進行排序,程序整體執行一遍的時間為7分鐘。刨掉出庫select的1分鐘,排序的時間在6分鐘左右。這么說來,還是有些慢。這個時候,更好的優化方式是將算法更改為hash,這樣時間復雜度將降為O(N),那么將會有質的提升,但是考慮到stl的map是紅黑樹實現,復雜度為O(N logN),并不是很好的選擇,而自己重新寫一個hash函數好像又比較麻煩。所以權衡了一下,還是繼續從排序入手。

最開始,想要將排序操作轉移到mysql上執行,也就是在出庫的同時進行排序,需要把出庫語句改為:

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

這樣之后,內存中只需要一次遍歷就好,時間開銷基本可以忽略,這條sql的執行時間為4分鐘,雖然相比于前面有了一些提升,但還是不夠理想,還需要進一步的優化。

在上文的程序中,我們發現全部的數據存儲在一個vector里,每一條數據為一個string,因此核心的開銷為string的operator < 比較操作。string是一個相對來說比較龐大的類,會造成許多的額外開銷。
我們只需要比較2個字段的唯一性,完全可以將這兩個字段拼接起來,存在一個char*中,之后的比較基于memcmp。
當然,可能有這樣的問題,第一條記錄的第一個字段為“123”,第二個字段為“456”;而第二條記錄的第一個字段為“12”,第二個字段為“3456”,這樣本來不等的兩個字段,拼接后相同。解決方式也很簡單,在“123”的結束位置加入一個特殊字符,再拼接,這樣就可以了。
在更改為char*之后,數據的排序時間從原來的3分鐘降到了40秒

目前來看,總體的執行時間為1分鐘40秒,其中出庫1分鐘,排序40秒。系統的整體瓶頸轉移到了出庫這里,這里的優化方式就相當明顯了,我們只是用到了2個字段,完全沒有必要select *,只需要將select語句改為:

select aaa.bbb, aaa.ccc from aaa;

這樣更改后,出庫的時間為13秒,整體的執行時間為50秒

這個時間,已經完全符合要求了,但是為了追求更高的速度,繼續將計算并行化,也就是說,充分利用cpu的多核計算能力,將任務盡可能的拆分為多個線程來完成。對于本例來說,我們并不需要整體有序的數據,因此,考慮hadoop的分桶思想,我們將取出的char*每位相加,得到的結果對10取余,將結果分散到10個線程去做,最后的執行結果為4秒鐘

經過上面的一步步優化,總共的執行時間為17秒
(原文時間2014-1-15)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,384評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,330評論 2 377

推薦閱讀更多精彩內容

  • 場景: 生產上發薪在過賬時過長,特別是發薪人數過多時,耗時非常巨大,嚴重影響發薪效率; 例如:廚房電器過賬人數1....
    小超_f598閱讀 642評論 0 0
  • 特別說明: 1、本文只是面對數據庫應用開發的程序員,不適合專業DBA,DBA在數據庫性能優化方面需要了解更多的知識...
    安易學車閱讀 1,843評論 0 40
  • SQL 優化(載錄于:http://m.jb51.net/article/5051.htm) 作者: (一)深入淺...
    yuantao123434閱讀 740評論 0 7
  • 原文:https://my.oschina.net/liuyuantao/blog/751438 查詢集API 參...
    陽光小鎮少爺閱讀 3,844評論 0 8
  • 風雨人生 文/火樹銀花 風 瘋夠了吧 回到家中息息腳吧 雨 淋透了吧 歸至港灣更更衣吧 人 混慘了...
    竹花閱讀 174評論 1 1