2017-02-16 62 views
1

說我有一個MongoDB的集合與文件是這樣的:

{ "_id": ObjectId("the_object_id"), 
    "type": "BLOG_POST", 
    "state": "IN_PROGRESS", 
    "createDate":ISODate("2017-02-15T01:01:01.000Z"), 
    "users": { 
     "posted": ["user1", "user2", "user3"], 
     "favorited": ["user1", "user4", "user5", "user6"], 
     "other_fields": "other data", 
    }, 
    "many_more_fields": "a bunch of other data" 
} 

我有這樣的查詢:

db.collection.find({"$and":[ 
    {"type": "BLOG_POST"}, 
    {"$or": [ {"users.posted":"userX"}, {"users.favorited":"userX"} ] }, 
    {"state": {"$ne":"COMPLETED"}} 
]}).sort({"createDate":1}) 

收集目前只有_id字段的索引和一些未包含在此查詢或示例中的字段。

就基數而言, type = BLOG_POST約爲集合的75%,state $ ne「COMPLETED」約爲集合的50%,且用戶位於users.posted或users最多隻有2%的收藏。

該用例的最佳索引或索引集合是什麼?

這是我的理解,我們不能索引users.posted和users.favorited在同一個索引,因爲他們都是數組。在未來,我們可能會創造出一批新的用戶。用戶認爲這是兩個領域的集合,但假設我們不能在短期內做出這樣的改變。

我還認爲$ ne狀態意味着通常不會使用狀態索引。查詢計劃者是否能夠在索引末尾的狀態字段處理$ ne條件?

我有一個指數{「類型」:1,「CREATEDATE」:1,「狀態」:1}的想法,以便查詢會打的類型,使用CREATEDATE的排序和處理$ ne與索引的最後一位。它仍然需要爲用戶測試35%-40%的文檔。不好,但比當前的收集掃描有所改進。或者我可以創建兩個索引,一個像{「users.posted」:1,「type」:1,「createDate」:1,「state」:1}和{「users.favorited」:1,2, 「type」:1,「createDate」:1,「state」:1}。 查詢計劃員是否會使用這兩個索引的交集來更快地找到感興趣的文檔?

我們目前正在使用MongoDB 3.2.5。如果MongoDB 3.2和3.4之間的答案存在差異,我很想知道它們。

回答

0

經過一番分析,我發現在和users.favorited中添加多個查詢作爲各個索引中的第一項都表現更好,並且由MongoDB查詢規劃器進行選擇。

我喜歡創建索引:

db.collection.createIndex({"users.posted":1, "type":1, "createDate":1, "state":1}) 
db.collection.createIndex({"users.favorited":1, "type":1, "createDate":1, "state":1}) 

由於對users.posted基數和users.favorited爲高(兩者之一將包括收集的不超過2%,大部分時間低於0.5%),MongoDB查詢規劃器使用索引交叉。

我測試了這對像一個指標:

db.collection.createIndex({"type":1, "createDate":1, "state":1}). 

回顧解釋對同時使用explain()explain("executionStats")兩個查詢計劃,查詢規劃器使用索引掃描爲{「$或」:[{」 users.posted「:」userX「},{」users.favorited「:」userX「}]}部分查詢作爲第一階段。這導致了最少的總體凱氏檢驗和totalDocs檢驗。