我有一个名为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