为啥 MongoDB 在这里使用 scanAndOrder?
Posted
技术标签:
【中文标题】为啥 MongoDB 在这里使用 scanAndOrder?【英文标题】:Why is MongoDB using scanAndOrder here?为什么 MongoDB 在这里使用 scanAndOrder? 【发布时间】: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 【参考方案1】:这似乎是 MongoDB 2.6.0-rc0 中的一个错误。在 MongoDB 2.4.9 中一切正常。
【讨论】:
【参考方案2】:Stefan 在这里报告了这个问题:http://jira.mongodb.org/browse/SERVER-12935 并且 scanAndOrder 问题在 2.6.0-rc0 之后得到解决,但解释输出存在一些挥之不去的问题。
【讨论】:
【参考方案3】:http://docs.mongodb.org/manual/reference/glossary/
自然顺序: 数据库在磁盘上存储文档的顺序。通常,磁盘上文档的顺序反映了插入顺序,除非文档在内部移动,因为更新操作会增加其大小。在有上限的集合中,插入顺序和自然顺序是相同的,因为文档不会在内部移动。对于不带参数的 find() 查询,MongoDB 以正向自然顺序返回文档。对于使用 $natural:-1 参数排序的 find() 查询,MongoDB 以逆自然顺序返回文档。见 $natural。
您对插入顺序 == 索引顺序的假设是错误的。
【讨论】:
这不是我的假设。我假设文档是按 endMS 排序的,因为 endMS 是复合索引的第二部分。 好了,你回答了你的问题。这是一个错误:)。如果我希望某个顺序只是为了确定,我总是使用排序,如果性能达不到标准,我会优化其他领域。以上是关于为啥 MongoDB 在这里使用 scanAndOrder?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我应该在 MongoDB 中使用 NodeJS 在会话案例中搜索用户?