2016-11-21 19 views
0
db.users.find({role:'seeker'}, { 
    "email": 1, 
    "name": 2 
}) 

至於建議,我跑什麼是最快的方式從MongoDB中的集合中選擇100萬用戶?

db.users.find({role:'seeker'}).explain() 

如果我使用上面的查詢需要15-20秒響應得到這個

{ 
    "queryPlanner" : { 
     "plannerVersion" : 1, 
     "namespace" : "users", 
     "indexFilterSet" : false, 
     "parsedQuery" : { 
      "role" : { 
       "$eq" : "seeker" 
      } 
     }, 
     "winningPlan" : { 
      "stage" : "COLLSCAN", 
      "filter" : { 
       "role" : { 
        "$eq" : "seeker" 
       } 
      }, 
      "direction" : "forward" 
     }, 
     "rejectedPlans" : [ ] 
    }, 
    "serverInfo" : { 

    }, 
    "ok" : 1 
} 

。我需要每天向批量用戶發送電子郵件廣告系列。我有一個Node.js的任務來完成,雖然這任務後臺運行,它會減慢一切即使node.js中是不應該被阻止

+0

從集合中獲取百萬個文檔是很多文檔,即使索引正確。你看過流式傳輸的結果,如[這裏](http://stackoverflow.com/a/21630141/1259510)所示? – JohnnyHK

+0

流媒體很有趣。我認爲這個使用案例存在超過10,000家公司toda,他們是怎麼做到的。例如讓我們說,LinkedIn必須在下午5點向所有人發送工作提醒郵件。 LinkedIn會從數據庫中提取多少封電子郵件,然後遍歷電子郵件數組中的每封電子郵件,找到匹配的作業+準備好的電子郵件模板,然後將該電子郵件發送給全世界100多個用戶100萬次 – PureText

回答

1

我認爲你正在做的是正確的。就像select email, name from student where role='student'

你有多少條記錄?無論如何,你是否已經調整了/ profile你的mongoDB實例?

你有指數role場? db.users.createIndex({ role: 1 })create-an-index-to-support-read-operations

您可以使用explain如果使用索引或沒有你查詢來獲取一些見解。

對於無法使用索引的查詢,MongoDB必須掃描集合中的所有文檔 以查找與查詢匹配的文檔。

如果電子郵件列表是相同的,那麼您每次都可以在您的應用中引入緩存?

+0

**索引角色**它在角色上創建索引是有意義的,但通常我們必須選擇整個數據庫,而不管角色是什麼 – PureText

+0

**解釋:**我運行db.users.find(query).explain()並將結果添加到問題(不能添加可讀代碼來評論)。 – PureText

+0

**無論如何調諧/配置你的mongoDB實例?**不,SQL背景。從來沒有用SQL來做。如何開始? – PureText

0

好了,所以添加索引後的解釋看起來是正確的,確實使用索引:

{ 
"queryPlanner" : { 
"plannerVersion" : 1, 
"namespace" : "users", 
"indexFilterSet" : false, 
"parsedQuery" : { 
"role" : { 
"$eq" : "seeker" 
} 
}, 
"winningPlan" : { 
"stage" : "FETCH", 
"inputStage" : { 
"stage" : "IXSCAN", 
"keyPattern" : { 
"role" : 1 
}, 
"indexName" : "role_1", 
"isMultiKey" : false, 
"direction" : "forward", 
"indexBounds" : { 
"role" : [ 
"[\"seeker\", \"seeker\"]" 
] 
} 
} 
}, 
"rejectedPlans" : [ ] 
}, 
"executionStats" : { 
"executionSuccess" : true, 
"nReturned" : 850834, 
"executionTimeMillis" : 13217, 
"totalKeysExamined" : 850834, 
"totalDocsExamined" : 850834, 
"executionStages" : { 
"stage" : "FETCH", 
"nReturned" : 850834, 
"executionTimeMillisEstimate" : 1970, 
"works" : 941141, 
"advanced" : 850834, 
"needTime" : 0, 
"needFetch" : 90306, 
"saveState" : 93946, 
"restoreState" : 93946, 
"isEOF" : 1, 
"invalidates" : 0, 
"docsExamined" : 850834, 
"alreadyHasObj" : 0, 
"inputStage" : { 
"stage" : "IXSCAN", 
"nReturned" : 850834, 
"executionTimeMillisEstimate" : 560, 
"works" : 850834, 
"advanced" : 850834, 
"needTime" : 0, 
"needFetch" : 0, 
"saveState" : 93946, 
"restoreState" : 93946, 
"isEOF" : 1, 
"invalidates" : 0, 
"keyPattern" : { 
"role" : 1 
}, 
"indexName" : "role_1", 
"isMultiKey" : false, 
"direction" : "forward", 
"indexBounds" : { 
"role" : [ 
"[\"seeker\", \"seeker\"]" 
] 
}, 
"keysExamined" : 850834, 
"dupsTested" : 0, 
"dupsDropped" : 0, 
"seenInvalidated" : 0, 
"matchTested" : 0 
} 
} 
}, 
"serverInfo" : { 
"host" : "xxx", 
"port" : 12345, 
"version" : "3.0.12", 
"gitVersion" : "33934938e0e95d534cebbaff656cde916b9c3573" 
}, 
"ok" : 1 
} 

我認爲這是你可以通過做得到最快的事「檢索一次全部」。 我不知道你是否能retrieve only specific fields,像「名」,只有「電子郵件」:

如果不指定推算,find()方法返回的 各個領域與查詢匹配的所有文件。

db.inventory.find({type:'food'})此操作將返回庫存集合中所有類型爲 字段值爲'food'的 文檔。返回的文件包含所有字段。

所以,如果你不想蒙戈返回的所有字段爲每一位學生,只是通過一些額外的參數,如:

db.users.find({ role: 'student' }, { name: 1, email: 1, _id:0 }) 

顯然讀取所有領域,從你的硬盤一個耗時的操作,因此,從10只獲取2場會給您的查詢顯著提升。在SQL方面,它是之間的差異:select * from Tselect name from T

我不知道你有沒有考慮使用分頁和配料接收/發送,即檢索學生的第一個10000,送他們發送電子郵件,然後檢索下一個10000級的學生,向他們發送電子郵件,重複..?

你也可以嘗試通過將你的mongo db實例中的用戶分割來進行橫向擴展,但這取決於你的硬件功能,我不認爲如果你只有一臺服務器,它會給你帶來任何好處。所以,分頁應該是一條路。

+0

感謝您複製解釋的結果,並花費您的時間和精力尋找解決方案。關於創建索引並選擇兩個字段我試過了,沒有太大的區別。當我10年前開始學習SQL時,這就是我準備好幾乎每本書的內容。有一個索引,並選擇你需要更快的查詢字段。但實際上,像linkedin/facebook這樣的網站每天發送超過100萬封個性化的電子郵件。 – PureText

+0

如果選擇電子郵件的時間超過15秒,每個電子郵件模板都需要進行個性化設置。那個cron任務會像內存一樣讓內存成爲垃圾。 – PureText

+0

此外,我嘗試在cron任務分頁,並瞭解到我不能相信跟蹤電子郵件發送到用戶1,用戶2,用戶3,並且需要發送給用戶4,用戶5,用戶6的事實該任務不能標記在用戶5上發送的電子郵件並且不斷地向他發送電子郵件,所以這種方法具有風險,非常危險的失敗點使我成爲訂戶 – PureText

相關問題