針對單一資料表進行擴容時優化速度的策略比較

2021-09-30 06:28:03 字數 2762 閱讀 6396

下面我們來開始針對資料表在擴容優化上的速度比較吧。

假設你的表結構是個3列的資料表,字段如下:

fromuid    touid    addtime

這個資料表隨著你的使用者和訪問量的增加,會急速增加。甚至會使你的程式在這裡成為瓶頸。那麼沒辦法,你需要對這張表進行擴容。而***要說的就是擴容的方案和一些在匯出資料時操作的細節,這些細節,能讓你優化表的速度得到很大的提公升^_^

我們假設這個資料表是innodb型別的,資料量超級大,100g吧(不要害怕,這裡面還有索引呢),但我們就假設他是100g。首先你要先知道檔案具體有多大,然後明確你想將每張表控制在多大(極限狀態),這樣做除法,你就能知道你要分多少張表了。這裡我們假設分成128張資料表。加上我們將單一表結構變成了既有發信箱又有收件箱,那麼原來的一張表就會變成128*2=256張表。

那麼我們來構造點兒資料吧。

假設fromuid是10位的,touid是10位的,addtime是乙個19位的完整時間,每列之間乙個/t佔1位,結尾乙個/n佔1位。每行就是43位元組。我們構造乙個1億行的資料。那麼大小正好是4g,這個檔案叫做test_data.log。他使我們下面測試的資料來源。

1、切分檔案。

首先,我們要將100g資料檔案的雜湊欄位都倒出(dba可不會幫你把檔案分割成好幾個再發給你,這是你需要做的工作)。

方法a:切分檔案我們第乙個想到的是linux系統自帶的split命令。假設我們每2千萬行切割乙個程式,這樣的話,1億行正好是5個檔案。

[root@localhost test_data]# time split -l 20000000 test_data.log new

real    0m15.128s

user    0m3.411s

sys     0m10.516s

這個經過測試就是最高效的,畢竟是系統級呼叫。我也是在同事質疑這個以後,而沒有直接用他切。唉~

方法b:同事說給我兩台高效能的機器,記憶體32g,其中16g劃分成記憶體盤。這樣的話,切割檔案的策略就變成,我可以一次性將2千萬資料先讀入16g記憶體盤,然後再執行mv指令將該檔案移動到磁碟。

這裡我還是用的每2千萬行資料儲存乙個檔案,也就意味著在記憶體中唯讀入了不到1g的內容。所以雖然這個方法的速度比split要慢,但我想,當我的真實資料到了以後,一次把16g記憶體都讀滿,速度應該有大幅提公升。

[root@localhost ~]# time php split_data.php

real    2m8.059s      <--這個數字隨著放入記憶體的記錄的增長,應該能減少很多。期待真實資料切分時的數值

user    1m55.013s

sys     0m12.888s

這裡有個細節需要指出:本來我最早寫的程式時採用error_log的第3種方式,追加到檔案的。但是同事說懷疑error_log在系統級是採用open,write,close三部操作的。還是建議我用fopen來建立控制代碼,然後不關閉控制代碼,來減少系統呼叫。所以我沒有測試呼叫error_log寫檔案會比我現有的方式慢多少。但網上說error_log在資料多了以後,好像效能會下降。

2、hash到檔案

方法a:每讀一行,根據fromuid進行一次hash,根據touid再進行一次hash,然後分別通過error_log或者fwrite方式寫入一條。這樣最省事兒,程式邏輯也最簡單。但是效率就不能保證了,相當於我們要有2億次對檔案的讀寫。天~~~   (不推薦)

方法b:我們應該充分發揮記憶體的功效,一次性盡可能多的讀入資料。還記得我上面把乙個檔案拆分成5個檔案了麼,如果這些檔案現在都小於我們的記憶體上限,那麼就一次性將檔案全讀到記憶體中,處理完了,再寫入新的檔案,這樣我們只有256此io操作(至少比寫2千萬次好很多吧)。

按照方法b:每2千萬讀入記憶體,再進行hash,其中hashtable的名稱作為陣列的key,每個值都進行連線。而後迴圈一次陣列,就把所有內容寫到hashtable對應的檔案中了。

測試一下效率:

[root@localhost ~]# time php hash_data.php

real    18m14.634s

user    17m57.038s

sys     0m17.429s

這樣的話,我們對乙個4g的檔案進行擴容,到切分檔案這步,只需要20分鐘。如果第一部用split的方法,應該能控制在18分鐘。別忘了,我們可有兩台伺服器,第一部切分完的資料分給另外伺服器一些,不就變成9分鐘了。按照我之前的估計,我們有30g資料的情況下,應該30g/4g*9=67.5min=1小時。快吧。

給我的機器是8核超執行緒,32g記憶體的機器,我肯定會把之前說的每2千萬行操作一次變成7千萬行的。這樣的速度期待吧。哈哈。

3、檔案匯入到資料庫

經過hash,每個檔案的大小可以控制在1g以下,所以我們這裡直接用mysqlimport這個命令。

在前兩步生成的檔案都是通過/t分隔的。mysqlimport命令可以穩定快速的錄入到對應的資料表中。(注,如果你的檔名稱叫from_**.sql,那麼匯入時,會自動將資料錄入到from_**表中)。

入過程中可以通過下面這個方法給匯入資料提速:

在匯入開始set autocomit=0;( 預設是1)

在導完後set autocomit=1;

此方法會導致磁碟io很高,負載也會極高。線上有服務不能用!!!!

寫完後,聽說還有同事倒過960g的~挑戰啊,看看我以後有沒有機會來一次吧,哈哈。

django刪除資料表以及對資料表進行改動更新

實在是氣的不行,被坑的太難受了,為了防止有人繼續走彎路,我來寫這篇文章了。本人屬於大學需要做專案,自己摸索著使用django,所以最開始django的資料庫就是個老大難的問題,當我生成的資料表我想刪除時,我去網上查了很多解答,那些辦法不僅複雜的不行,還無數次的把我的資料庫整崩,然後我就不斷的重新建新...

MySQL對資料表已有表進行分割槽表

對現有的乙個表進行建立分割槽表,並把資料遷移到新錶,可以按時間來分割槽,然後這錶不是實時更新,每天有一次插入操作。時間比較充裕,但是伺服器上有其他應用,使用較小資源為主要方式。1 可以使用alter table來進行更改表為分割槽表,這個操作會建立乙個分割槽表,然後自動進行資料copy然後刪除原表,...

資料表中,對上條記錄進行操作

有如下表 客戶 客戶名稱 單據日期 本期應收 本期應付 01 北京 2004 1 1 1000 0 01 北京 2004 2 1 100 0 01 北京 2004 3 1 0 200 01 北京 2004 4 1 500 200 01 北京 2004 5 1 500 0 02 上海 2004 1 1...