2013-07-23 51 views
0

我已經寫一個Python腳本插入一些數據(300百萬)到MySQL表:Python:我的多進程代碼插入到MySQL有什麼問題?

#!/usr/bin/python 

import os 
import MySQLdb 

from multiprocessing import Pool 

class DB(object): 

    def __init__(self): 
    self.conn = MySQLdb.connect(host='localhost',user='root',passwd='xxx',db='xdd',port=3306) 
    self.cur = self.conn.cursor() 

    def insert(self, arr): 
    self.cur.execute('insert into RAW_DATA values(null,%s,%s,%s,%s,%s,%s,%s)', arr) 

    def close(self): 
    self.conn.commit() 
    self.cur.close() 
    self.conn.close() 


def Import(fname): 
    db = DB() 

    print 'importing ', fname 
    with open('data/'+fname, 'r') as f: 

    for line in f: 
     arr = line.split() 
     db.insert(arr) 

    db.close() 


if __name__ == '__main__': 
    # 800+ files 
    files = [d for d in os.listdir('data') if d[-3:]=='txt'] 

    pool = Pool(processes = 10) 
    pool.map(Import, files) 

的問題是,腳本運行速度非常非常慢,有沒有使用多的任何明顯的錯誤?

+0

您應該運行一個分析器來檢查數據庫後端是否正在佔用所有時間。 – hivert

+0

你爲什麼要並行化一個I/O綁定的任務? – kindall

回答

3

是的,如果你在同一個表中批量插入3億行,那麼你不應該嘗試並行化插入。所有插入必須經歷相同的瓶頸:更新索引,並寫入硬盤上的物理文件。這些操作需要獨佔訪問底層資源(索引或磁盤頭)。

實際上,您正在爲數據庫添加一些無用的開銷,而這些開銷現在必須處理多個併發事務。這會消耗內存,強制上下文切換,使磁盤讀取頭始終跳轉,等等。

將所有內容插入到同一個線程中。


看起來你實際上是從一種CSV文件導入數據。您可能想要使用內置的LOAD DATA INFILE MySQL命令,專門用於此目的。如果您在調整此命令時需要一些幫助,請描述您的源文件。

+0

謝謝!事實上,我簡化了代碼,在插入之前我需要做一些文本處理工作。我可以使用分區來加速嗎? – MrROY

+0

如果您的分區位於不同的物理磁盤上,分區*可能會有所幫助。您的硬盤很可能是限制因素。此外,如果源文件與數據庫文件位於同一磁盤上,則只需讀取一些I/O時間即可。請監視您的系統並確認CPU或HDD是否是瓶頸。一個簡單的'頂部'會做。如果您的CPU使用率低於100%,或者其大部分時間花費在「IO等待」中,那麼硬盤是限制因素。 – RandomSeed

+0

請讓我們知道該表是InnoDB還是MyISAM。 – RandomSeed