2016-09-10 64 views
2

我有一個包含150萬個文檔的mongoDB集合,所有這些文檔都具有相同的字段,並且我想將Field A的內容(每個文檔都獨一無二)和在其上執行f(A),然後創建並在Python填充字段B僞代碼:對MongoDB實例中的每個文檔執行操作

for i in collection.find(): 
    x = i**2 
    collection.update(i,x) #update i with x 

注:據我所知,更新代碼可能是錯的,但除非它影響操作的速度,我選擇了離開它那裏爲了簡單起見

問題是,這段代碼真的很慢,主要是因爲它可以通過1000個文件大約一秒鐘,然後服務器切斷光標大約一分鐘,然後它允許另一個1000.我想知道是否有任何方法來優化此操作,或者如果我堅持這個緩慢的瓶頸。

其他注意事項:

  1. 我已經調整batch_size作爲一個實驗,它是速度更快,但它的效率不高,而且還需要幾個小時

  2. 我也知道,SQL也許可以做到這一點更快,還有其他一些原因,我使用的是與此問題無關的noSQL DB

  3. 該實例正在本地運行,因此出於所有意圖和目的,沒有網絡延遲

  4. 我見過this問題,但它的回答並沒有真正解決我的問題

回答

0

數據庫客戶往往從實際的數據庫活動是非常抽象的,所以觀測延遲的行爲是有欺騙性的。在這段時間內,您可能實際上正在敲擊數據庫,但是這個活動對於Python解釋器來說都是隱藏的。

也就是說,你可以做一些事情來做到這一點。

1)在您正在進行更新的屬性A上添加一個索引。這將使它返回更快。

2)把你的電話find投影算:

for doc in collection.find(projection=['A']): 

這將確保你只返回你需要的領域,如果你正確索引獨特A財產,將確保您的結果完全來自非常快速的指數。

3)使用更新操作符來確保您只需要發回新字段。而不是發送整個文件,發回詞典:

{'$set': {'B': a**2}} 

將每個文檔中創建字段B不影響任何其他內容。

所以,整個街區將是這樣的:

for doc in collection.find(projection=['A', '_id']): 
    collection.update(filter={'_id': doc['_id']}, 
         update={'$set': {'B': doc['A']**2}}) 

這應該對蒙戈所要做的,以及工作顯着地減少(目前不相干的你)網絡流量。

+0

謝謝,我已經使用的投影和'$ set',但我會考慮的指數點 –

0

也許你應該在多個線程中進行更新。我認爲在一個線程中加載數據可能會更好,可以將其拆分成多個部分,並將這些部分傳遞給並行工作線程來執行更新。它會更快。

編輯:

我建議你做分頁查詢。 Python的僞代碼:

count = collection.count() 
page_size = 20 
i = 0; 
while(i < count): 
    for row in collection.find().limit(pageSize).skip(i): 
     x = i**2 
     collection.update(i, x); 
    i += page_size 
+0

由於它是mongod的情況下造成的瓶頸,而不是處理電力,這並不能很好地工作,我試過了 –

+0

我有另一種選擇。請參閱我答案中的編輯部分 –

相關問題