2014-02-12 203 views
0

所以我有一個MongoDB實例,我試圖用另一個集合中的數據更新一個集合中的數據。這兩個藏品是participants約180k文件和questions約95k文件。性能調優MongoDB查詢/更新?

participants文檔通常是這個樣子:

{ 
    "_id" : ObjectId("52f90b8bbab16dd8594b82b4"), 
    "answers" : [ 
     { 
      "_id" : ObjectId("52f90b8bbab16dd8594b82b9"), 
      "question_id" : 2081, 
      "sub_id" : null, 
      "values" : [ 
       "Yes" 
      ] 
     }, 
     { 
      "_id" : ObjectId("52f90b8bbab16dd8594b82b8"), 
      "question_id" : 2082, 
      "sub_id" : 123, 
      "values" : [ 
       "Would prefer to go alone" 
      ] 
     }, 
     { 
      "_id" : ObjectId("52f90b8bbab16dd8594b82b7"), 
      "question_id" : 2082, 
      "sub_id" : 456, 
      "values" : [ 
       "Yes" 
      ] 
     } 
    ], 
    "created" : ISODate("2012-03-01T17:40:21Z"), 
    "email" : "anonymous", 
    "id" : 65, 
    "survey" : ObjectId("52f41d579af1ff4221399a7b"), 
    "survey_id" : 374 
} 

我使用下面的查詢來執行更新:

db.participants.ensureIndex({"answers.question_id": 1, "answers.sub_id": 1}); 
print("created index for answer arrays!") 
db.questions.find().forEach(function(doc){ 
    db.participants.update(
     { 
      "answers.question_id": doc.id, 
      "answers.sub_id": doc.sub_id 
     }, 
     { 
      $set: 
      { 
       "answers.$.question": doc._id 
      } 

     }, 
     false, 
     true 
    ); 
}); 
db.participants.dropIndex({"answers.question_id": 1, "answers.sub_id": 1}); 

但是,這需要大約20分鐘才能運行。我希望添加索引對性能有幫助,但它仍然很慢。考慮到我在索引對象數組中的字段,這個索引設置是否正確?任何人都可以看到我正在做的事情會導致緩慢?從哪裏開始尋找改善此查詢性能的建議?

+0

查詢後調用dropIndex有什麼意義? 你的查詢的「explain()」結果如何? db.participants.find({ 「answers.question_id」:doc.id, 「answers.sub_id」:doc.sub_id })解釋() – yaoxing

+0

我認爲這將是很多,如果你能表達得更快。它作爲一個mapreduce作業,這樣它將全部在數據庫服務器上執行而不涉及網絡。 – leif

+0

只是爲了澄清,沒有一個單獨的應用程序正在執行此腳本。這是一個純粹的MongoDB腳本,我從shell執行。這就是說,你是否仍然認爲網絡涉及? –

回答

0

如果有人有興趣,我能夠藉此更新查詢的運行時間由20分鐘降低到約在選擇questions文件時通過使用投影分鐘半。由於我只使用了_ididsub_id領域我能做到以下幾點:

db.questions.find({},{_id: 1, id: 1, sub_id: 1}).forEach(function(doc){ 
    .... 

從而大大提高了性能。希望這可以幫助別人!

1

我認爲你需要考慮你在做什麼爲了理解爲什麼索引沒有幫助,甚至爲什麼這個操作需要這麼長時間。

答案的第一部分是由你在這裏做什麼解釋:

db.questions.find() 

現在單獨的部分基本上說,你問你的questions集合檢索每個文檔。因此,我們可以看到您正在嘗試執行的操作就是如此,因爲您希望將該內容更新到participants集合中,特別是「問題」的文檔_id。但是在這裏,根據獲取所有文檔的定義,不會使用索引。

所以,你在做什麼是循環的questions每個文檔,然後用你的更新操作比賽participants記錄與數據從「問題」詢問。而這意味着您將95K文檔中的所有95K文檔「通過電纜」拉出,並通過95K次「更新線路」更新操作。這不會發生在服務器上,並且您的應用程序和MongoDB之間存在網絡流量。

索引本身除了改進每個participants記錄的搜索外,並不會做太多的工作,這比掃描更好,您應該可以獲得匹配結果。但這不是花時間的部分,它是取得最大問題的questions。另外請注意,如果您正在更新

因此,如果可以在儘可能接近MongoDB服務器網絡條件的計算機上運行更新過程,那麼這將是您最佳的性能改進。如果您希望有點大膽和/或可以在另一個操作中檢查完整性,那麼您也可以撤回Write Concern,並且這會減少網絡流量並等待對更新的響應(實際上正在發生),如果你把它放在「火,忘了」模式。

另請參見指南,如果你不知道的概念:

http://docs.mongodb.org/manual/core/write-concern/

+0

只是爲了說明,沒有單獨的應用程序正在執行此腳本。這是一個純粹的MongoDB腳本,我從shell執行。有了這個說法,你的「過網」問題仍然適用嗎? –

+0

是的。 shell只是另一個客戶端。你沒有在服務器上執行,這是我以爲你認爲你在做什麼。 –

+0

哦,有趣的是,它有可能在服務器上執行嗎?我的客戶端和服務器在同一臺機器上運行...... –