我有一个名为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检索结果至少需要十分钟,并且令人好奇的是,它可以扫描 7000万 个对象来完成此任务,这是通过 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版本。)
my_namespace
,然后获取该日期之间的所有文档等等。尝试重新排序索引,使post_time排在第一位。 - Sammaye