2015-05-19 29 views
0

想象一下包含大約5,000,000個文檔的集合。我需要做一個basicCursor查詢來選擇基於太多字段進行索引的〜100個文檔。我們稱之爲basicCursorMatch。這將非常緩慢。我可以在MongoDB光標上做第二個'查詢'嗎?

但是我可以在bTreeCursor上查詢幾個索引,這會限制我的搜索到500個文檔。我們稱這個查詢爲bTreeCursorMatch

有沒有一種方法可以直接在上做遊標或從bTreeCursorMatch產生的集合?

憑直覺我試圖

var cursor = collection.find(bTreeCursorMatch); 
var results = cursor.find(basicCursorMatch); 

類似collection.find(bTreeCursorMatch).find(basicCursorMatch),這似乎並沒有工作。

另外,我希望我可以做這樣的事情:

collection.aggregate([ 
    {$match: bTreeCursorMatch}, // Uses index 5,000,000 -> 500 fast 
    {$match: basicCursorMatch}, // No index, 500 -> 100 'slow' 
    {$sort} 
]); 

..但似乎我不能做到這一點無論是。有沒有別的辦法可以做我想做的事?

我問的原因是因爲這第二個查詢將有很大的不同,我沒有辦法索引所有的字段。但我確實希望使用bTreeCursor進行第一個查詢,否則查詢整個集合將永遠使用basicCursor

更新

此外,通過用戶輸入的文檔500的部分選定將被以不同的方式在會話期間與不可預測的basicCursor查詢查詢,使用多個$in$eq$gt$lt。但在此期間,bTreeCursor子選舉仍然相同。我應該繼續爲每個用戶查詢做兩個查詢嗎,還是有一種更有效的方法來保存這個集合的reference

+0

您不能連接查詢,因爲遊標在數據庫中'實時',它們已經包含查詢和光標位置。但是,您可以簡單地在查詢末尾追加附加條件*,或者強制使用索引。 – mnemosyn

+1

使用兩個$ match元素定義聚合管道可行。你收到了什麼錯誤信息? –

+0

@Pascal Bugnion認真嗎?那我一定做錯了。我會盡快再試一次。這會爲第一個查詢使用索引嗎?或者它會合並查詢並使用基本光標?我使用的是MongoDB'2.4',也許這兩個$匹配需要'3.0'? – Redsandro

回答

1

實際上,您很少需要在遊標上運行第二個查詢。您特別不需要將MongoDB的工作分解爲單獨的可索引/不可索引塊。

如果您向MongoDB的find方法傳遞查詢,那麼可以通過在索引中查找來部分滿足該方法,MongoDB將首先執行查找,然後對其餘文檔執行全面掃描。

舉例來說,我有一個集合users與像文件:

{ _id : 4, gender : "M", ... } 

有一個指數_id,但不是性別。在users有~200M文件。

想了解一下MongoDB是引擎蓋下做的一個想法,添加explain()你的光標(在蒙戈外殼):

> db.users.find({ _id : { $gte : 1, $lt : 10 } }).explain() 
{ 
    "cursor" : "BtreeCursor oldId_1_state_1", 
    "n" : 9, 
    "nscannedObjects" : 9 
} 

我已經削減了一些由explain返回的字段。基本上,光標會告訴你它是否使用索引,n告訴你查詢返回的文檔數,而nscannedObjects是查詢過程中掃描的對象數。在這種情況下,mongodb能夠精確掃描正確數量的對象。

如果我們現在查詢性別,會發生什麼?

> db.users.find({ _id : { $gte : 1, $lt : 10 }, gender : "F" }).explain() 
{ 
    "cursor" : "BtreeCursor oldId_1_state_1", 
    "n" : 5, 
    "nscannedObjects" : 9 
} 

find返回5個對象,但必須掃描9個文檔。因此,它能夠使用_id字段隔離正確的9個文檔。然後它通過所有9個文件並按性別過濾它們。

+0

謝謝。我現在已經提出了這個答案(以及之前的評論)。不過,我不確定這個答案是否足夠先進。我會讚揚努力增加一點複雜性。例如,實際上我經常發現'explain'返回3或5個具有不同索引的計劃和遊標。我已經使用基本解釋來驗證我的查詢,但是多個計劃是它令人困惑的地方。此外,處理文檔的半永久性選擇(參見編輯)未得到解決。例如。你會簡單地爲每個「子查詢」合併兩個查詢對象嗎? – Redsandro

+1

我對你的評論有點困惑。在'find'上調用'explain'會返回一個計劃。如果您運行'db.collection.find()。explain({verbose:true})',您會得到一個名爲'allPlans'的額外子文檔,其中包含可能應用於查詢的所有計劃。使用的計劃是解釋文檔頂層的計劃。 –

+1

當您使用'{explain:true}'運行聚合時,您會爲聚合管道中的每個階段獲得一個計劃(MongoDB還會添加allPlans子文檔,該文檔列出了該階段考慮的所有計劃,但是頂層計劃是實際執行的計劃)。 –

相關問題