我有一個名爲post
的MongoDB集合與3500萬對象。該集合有兩個二級索引,定義如下。多鍵索引慢範圍查詢
> db.post.getIndexKeys()
[
{
"_id" : 1
},
{
"namespace" : 1,
"domain" : 1,
"post_id" : 1
},
{
"namespace" : 1,
"post_time" : 1,
"tags" : 1 // this is an array field
}
]
我期待下面的查詢,它只是通過namespace
和post_time
過濾器,在合理的時間內沒有掃描所有對象上運行。
>db.post.find({post_time: {"$gte" : ISODate("2013-04-09T00:00:00Z"), "$lt" : ISODate("2013-04-09T01:00:00Z")}, namespace: "my_namespace"}).count()
7408
但是,它需要MongoDB的至少十分鐘,檢索結果和,奇怪的是,它管理掃描對象根據explain
函數來完成這項工作。
> db.post.find({post_time: {"$gte" : ISODate("2013-04-09T00:00:00Z"), "$lt" : ISODate("2013-04-09T01:00:00Z")}, namespace: "my_namespace"}).explain()
{
"cursor" : "BtreeCursor namespace_1_post_time_1_tags_1",
"isMultiKey" : true,
"n" : 7408,
"nscannedObjects" : 69999186,
"nscanned" : 69999186,
"nscannedObjectsAllPlans" : 69999186,
"nscannedAllPlans" : 69999186,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 378967,
"nChunkSkips" : 0,
"millis" : 290048,
"indexBounds" : {
"namespace" : [
[
"my_namespace",
"my_namespace"
]
],
"post_time" : [
[
ISODate("2013-04-09T00:00:00Z"),
ISODate("292278995-01--2147483647T07:12:56.808Z")
]
],
"tags" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : "localhost:27017"
}
對象的數目和掃描的次數之間的差必須由標籤陣列(其均等於2)的長度而引起的。不過,我不明白爲什麼post_time
過濾器不利用索引。
你能告訴我我可能會錯過什麼嗎?
(我工作的下降機器上24個核心和96 GB的RAM,我使用MongoDB的2.2.3。)
命名空間的基數是否已經很低? – Sammaye 2013-05-09 11:20:05
目前,只有一個不同的'namespace'值,這是我正在使用的值。 – 2013-05-09 11:20:59
是的,這就是爲什麼,MongoDB必須首先限制第一個字段,因此它獲得所有'my_namespace',然後獲取該日期之間的所有文檔等等,嘗試重新排序索引以便post_time是第一個 – Sammaye 2013-05-09 11:21:50