Ese*_*gün 6 indexing mongodb mongodb-indexes
我有一个名为MongoDB的集合post与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
}
]
Run Code Online (Sandbox Code Playgroud)
我希望以下查询,只需过滤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
Run Code Online (Sandbox Code Playgroud)
然而,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"
}
Run Code Online (Sandbox Code Playgroud)
对象数量和扫描次数之间的差异必须由标签阵列的长度(均等于2)引起.不过,我不明白为什么post_time过滤器不使用索引.
你能告诉我我可能会缺少什么吗?
(我正在使用24核和96 GB RAM的下降机.我使用的是MongoDB 2.2.3.)
在这个问题中找到了我的答案:Order of $lt and $gt in MongoDB range query
我的索引是多键索引(在tags),并且我正在运行范围查询(在post_time)。显然,在这种情况下,MongoDB 无法使用范围的两侧作为过滤器,因此它只选择$gte第一个子句。由于我的下限恰好是最低post_time值,MongoDB 开始扫描所有对象。
不幸的是,这并不是故事的全部。为了解决这个问题,我也创建了非多键索引,但 MongoDB 坚持使用坏索引。这让我认为问题出在其他地方。最后,我不得不放弃多键索引并创建一个没有该tags字段的索引。现在一切都很好。
| 归档时间: |
|
| 查看次数: |
1349 次 |
| 最近记录: |