2015-11-21 80 views
3

我有一些元數據和大量項目的這個對象。我曾經將它存儲在mongo中,並通過$unwind查詢它。然而,在極端情況下,陣列變得如此之大以至於我遇到了16MB的BSON限制。如何提高MongoDB批量性能?

所以我需要在陣列中的每個元素存儲爲一個單獨的文件。爲此,我需要將元數據添加到所有這些元數據中,以便我可以找回它們。 It is suggested that I use bulk operations爲此。

然而,表現似乎很慢。將一個大文件是近乎即時的,這需要長達10秒

var bulk  = col.initializeOrderedBulkOp(); 
var metaData = { 
    hash   : hash, 
    date   : timestamp, 
    name   : name 
}; 

// measure time here 

for (var i = 0, l = array.length; i < l; i++) { // 6000 items 
    var item = array[i]; 

    bulk.insert({ // Apparently, this 6000 times takes 2.9 seconds 
     data  : item, 
     metaData : metaData 
    }); 

} 

bulk.execute(bulkOpts, function(err, result) { // and this takes 6.5 seconds 
    // measure time here 
}); 

批量插入6000個文件,總共38 MB數據價值(這相當於49 MB爲BSON在MongoDB中),表現似乎不可接受的糟糕。 將元數據附加到每個文檔的開銷不會那麼糟糕,對吧?更新兩個索引的開銷不會那麼糟糕,對吧?

我錯過了什麼嗎?是否有更好的方式來插入需要作爲一個組提取的文檔組?

這不只是我的筆記本電腦。在服務器上相同。讓我覺得這不是一個配置錯誤,而是一個編程錯誤。

使用的MongoDB 2.6.11與節點適配器node-mongodb-native 2.0.49

-update-

添加元數據,以在本體帳戶的每個元素爲2.9秒的僅有的行爲。這需要有一個更好的方法。

+0

注意不是「內部」兩個司機和MongoDB本身會在一時間打破這種下降到1000點的操作(因而這實際上做6發送/接收交互),也沒有任何一個請求實際上可以超過16MB,因此無論如何都有一些「分手」這個請求。還要考慮到,因爲正在調用'bulk.insert()',那麼實際上並沒有發送到服務器,而是在內存中建立數據(第二次有效)。直接通過閱讀來源,你會更好地接近這一點。另外,將相同的數據添加到所有內容有什麼意義? –

+0

我需要能夠找到分組的數據。例如。來自'timestamp'的60000個文件,其中10000個具有相同的'name'和6000個'hash'。但是哈希也出現在不同的時間戳中。我需要選擇這三個屬性的組合。我只是試圖模仿我將所有文檔放入單個文檔中時所做的操作。這是我從Stack Overflow得到的答案,但如果你有更好的主意,請成爲我的客人! :) – Redsandro

+0

可能對您的建模目標有點寬泛,沒有具體問題。但是,對於眼前的問題,卻有一點偏離主題。所以你有一個60,000個文件的數組。你從哪裏得到它?你能否包含源代碼的讀取代碼?因爲我不確定你是否在存儲內存中存儲了60,000個文檔,因此在完成任何事情之前再次將60,000個文檔的另一個副本存儲在內存中。如果可以直接從源代碼處理塊,我認爲這將獲得更好的吞吐量。 –

回答

0

發送批量插入操作,分批,因爲這將導致更少到服務器的通信,從而通過在所有的個別語句不發送一切,而是分解成可管理的塊服務器進行承諾高效絲交易。採用這種方法等待回調中的響應的時間也更少。

更好的方法是使用模塊,因此即使循環輸入列表也是非阻塞操作。選擇批量大小可以變化,但每選擇1000個條目批量插入操作將使其安全地留下16MB BSON硬限制,作爲整個「請求」等於一個BSON文件。

以下演示使用async模塊的同時遍歷數組並重復調用迭代器函數,而測試返回true。停止時或發生錯誤時調用回叫。

var bulk = col.initializeOrderedBulkOp(), 
    counter = 0, 
    len = array.length, 
    buildModel = function(index){ 
     return { 
      "data": array[index], 
      "metaData": { 
       "hash": hash, 
       "date": timestamp, 
       "name": name 
      } 
     } 
    }; 

async.whilst(
    // Iterator condition 
    function() { return counter < len }, 

    // Do this in the iterator 
    function (callback) { 
     counter++; 
     var model = buildModel(counter); 
     bulk.insert(model); 

     if (counter % 1000 == 0) { 
      bulk.execute(function(err, result) { 
       bulk = col.initializeOrderedBulkOp(); 
       callback(err); 
      }); 
     } else { 
      callback(); 
     } 
    }, 

    // When all is done 
    function(err) { 
     if (counter % 1000 != 0) { 
      bulk.execute(function(err, result) { 
       console.log("More inserts."); 
      }); 
     }   
     console.log("All done now!"); 
    } 
); 
+3

Mongo會自動執行此操作。缺省值(限制)爲1000.您應該僅出於特定原因執行此操作,例如,如果1000個文檔已超過16MB限制,則可以手動執行。但是你需要取一個小於1000的數字纔有意義。 – Redsandro