2017-10-18 69 views
1

我在MongoDB中遇到插入速度非常慢(大約200秒/插入),我完全不知道爲什麼。PyMongo插入令人震驚的慢數據庫,大約有100M記錄

我有一個匿名用戶名(整數),匿名評論ID(整數)和評論的CSV文件。所有這些都以字符串形式讀入,但前兩個字段可以毫無問題地轉換爲整數。

該數據庫包含100M記錄的集合,現在正嘗試構建映射用戶及其註釋ID,將其寫入另一個集合。 大約有60K用戶發佈了100M評論。這是爲每個用戶構建user_id = [comment_id0,...,comment_idN]並將其插入到數據庫中,以便更快地獲取所有用戶註釋。

def save_user_comments(dataset): 
    usrs = defaultdict(list) 
    updatebar = tqdm(total = 100000000, desc = 'Generating user-comment map', leave = False) 
    pool = mp.Pool() 

    for i, (user_id, comment_id, _) in enumerate(dataset): 
     usrs[str(user_id)].append(comment_id) 
     updatebar.update(1) 

    prev = 0 
    keys, vals = list(usrs.keys()), list(usrs.values()) 
    results = pool.map_async(write_user, zip(keys, vals)).get() 

progbar = tqdm(total = 67377, desc = 'Users Inserted', leave = False) 
def write_user(itempair): 
    usr, comments = itempair 

    db = MongoClient(host = some_ip, port = some_port).GenderSpectrum 
    table = db.user 

    if db.user.find_one({'user_id': str(usr)}): 
     progbar.update(1) 
     return 

    u_obj = {} 
    obj = db.data.find_one({'user_id': str(usr)}) 

    u_obj['comment_ids'] = comments 
    u_obj['_id'] = str(usr) 
    u_obj['is_female'] = obj['is_female'] 
    u_obj['user_id'] = str(usr) 
    db.user.insert_one(u_obj) 
    progbar.update(1) 
    return 1 

我在這段代碼中看到的唯一會減慢速度的事情是爲每個插入創建一個新的連接。但是,嘗試使用一個連接(使用單個和多個文檔插入)插入批量的500個文檔時,速度更慢。所以按順序運行這個代碼。

有人有更好的建議嗎?

MongoDB的版本:v3.4.9

PyMongo版本:3.5.1

Python版本:3.5.3

操作系統:Ubuntu的17.4

+0

我發現很難相信批量插入可能比許多'insert_one'連續運行慢,因爲單個操作會涉及更多的開銷。這意味着代碼的緩慢部分不在MongoDB一方,而是在另一部分。可能是正在創建新文檔的部分。你有沒有嘗試使用cProfile分析? –

+0

批量插入運行約300s /迭代與個人200s /迭代。這對我來說沒有任何意義。我確實嘗試了分析,但沒有看起來可疑。我正在驗證創建索引是否有幫助(它看起來已經完成了)。 – ZeerakW

回答

2

插入本身可能是非常快的,你的循環的其他部分很可能很慢。如果「USER_ID」沒有被索引,那麼這可能是緩慢的部分:

db.data.find_one({'user_id': str(usr)}) 

在「數據」收集創建於user_ID的指數。只需執行一次:

db.data.create_index([('user_id', 1)]) 

這可能需要幾分鐘,之後「find_one」會快得多。

您還爲每個插入創建一個新的MongoClient,這也會使您的代碼變慢一點。在您的程序期間創建一次MongoClient:將其聲明爲全局變量,而不是「write_user」函​​數中的局部變量。

+0

Mongo文檔明確指出,不應該創建一個全局客戶端,而是每個進程都有一個。創建索引似乎可以加快速度(沒有意識到你可以這麼做!),一旦我確認了它,我會更新它。 – ZeerakW

+0

創建索引的確有竅門。 – ZeerakW

+0

「每個進程一個MongoClient」是正確的 - 一個進程是一個Python程序。您在執行「python myscript.py」時創建一個進程。你的代碼顯示的是爲每個函數調用創建一個MongoClient,這會比應該慢。我建議創建MongoClient作爲全局變量,以便它持續Python程序的持續時間。 –

相關問題