【发布时间】:2014-02-26 19:37:40
【问题描述】:
我正在 MongoDB 中保存游戏文档。除其他内容外,这些文件还包含玩家的姓名 (name)、游戏结束的时间 (endMS) 和游戏的类型 (type)。类型可以有五分之一的不同值。
我需要搜索按游戏结束时间排序的玩家完成的所有游戏,以及按游戏结束时间排序的特定游戏类型的玩家完成的所有游戏。
这两个查询的示例是
db.games.find({name:"Stefan",endMS:{$gt:0}}).sort({endMS:-1})
和
db.games.find({name:"Stefan",type:"bli",endMS:{$gt:0}}).sort({endMS:-1})
你可以使用索引
db.games.ensureIndex({name:1,endMS:-1})
和
db.games.ensureIndex({name:1,type:1,endMS:-1})
为了快速访问。
现在我尝试只使用一个索引:
db.games.ensureIndex({name:1,endMS:-1,type:1})
第一个查询或课程仍然运行良好。第二个查询的想法是,Mongo 在扫描索引时可能需要跳过一些条目,但只需要访问查询最终返回的文档,因为“类型”已经可以在索引中检查。这应该足以满足我的需要。
但是使用 explain() MongoDB 告诉我在像这样查询数据库时需要“scanAndOrder”。
db.games.find({name:"Stefan",type:"bli",endMS:{$gt:0}}).sort({endMS:-1}).explain()
{
"cursor" : "BtreeCursor name_1_endMS_-1_type_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 22,
"nscannedObjectsAllPlans" : 4,
"nscannedAllPlans" : 25,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"name" : [
[
"Stefan",
"Stefan"
]
],
"endMS" : [
[
Infinity,
0
]
],
"type" : [
[
"bli",
"bli"
]
]
},
"server" : "localhost:27017",
"filterSet" : false
}
nscannedObjects 和 nscanned 如上所述,但我想知道为什么 Mongo 说 scanAndOrder:true。
根据文档: “scanAndOrder 是一个布尔值,当查询不能使用索引中文档的顺序返回排序结果时为真:MongoDB 必须在从游标接收文档后对文档进行排序。”
据我了解,文档应该在索引中排序,只需要跳过一些不影响顺序的文档。
那么为什么 MongoDB 在这里使用 scanAndOrder 呢?
【问题讨论】:
-
您使用的是哪个版本的 MongoDB?奇怪的是,您有一个真正的“scanAndOrder”和一个错误的“indexOnly”。我会说您的查询已被索引覆盖...
-
我使用的是 MongoDB 2.6.0-rc0。搜索不能是 indexOnly,因为它返回整个文档。它只是“indexOnly”,因为它不需要扫描文档来确定它是否与查询匹配。
-
奇怪,我已将 {_id:0,name:1} 作为投影参数添加到查询中,这也不会使查询 indexOnly。它可能与“type”实际上是“tc.type”有关,因此它取自嵌入式文档(我只是想让这里的问题更清楚)。我记得当索引的一部分来自嵌入文档时,MongoDB 的聚合框架中的coveredIndexes 存在问题。但这是否也会影响 scanAndOrder?
-
我做了更多的测试,似乎从嵌入文档中获取的索引条目在这里不是问题。
-
我会用 2.4 版本测试它。如果这是一个错误,你应该check this
标签: mongodb mongodb-query