我在mongo中有一个查询,我想优先考虑第一个字段,然后是第二个字段。
说我必须查询
db.col.find({category: A}).sort({updated: -1, rating: -1}).limit(10).explain()
所以我创建了以下索引
db.col.ensureIndex({category: 1, rating: -1, updated: -1})
它可以根据需要对多个对象进行精细扫描,即10
。
但现在我需要查询
db.col.find({category: { $ne: A}}).sort({updated: -1, rating: -1}).limit(10)
所以我创建了以下索引:
db.col.ensureIndex({rating: -1, updated: -1})
但这导致扫描整个文档以及何时创建
db.col.ensureIndex({ updated: -1 ,rating: -1})
它扫描的文档数量较少:
我只想要清楚地了解多个字段的排序以及这样做时要保留的顺序是什么。通过阅读MongoDB文档,我们需要执行排序的字段应该是最后一个字段。这就是我在上面的$ne
查询中假设的情况。我做错了吗?
答案 0 :(得分:30)
MongoDB query optimizer通过尝试不同的计划来确定哪种方法最适合给定查询。然后,针对下一个~1,000个查询缓存该查询模式的获胜计划,或直到您执行explain()
。
要了解考虑了哪些查询计划,您应该使用explain(1)
,例如:
db.col.find({category:'A'}).sort({updated: -1}).explain(1)
allPlans
详细信息将显示所有已比较的计划。
如果您运行的查询不是很有选择性(例如,如果许多记录符合您的{category: { $ne:'A'}}
条件),MongoDB使用BasicCursor(表扫描)查找结果而不是匹配可能会更快反对索引。
查询中字段的顺序通常对索引选择没有影响(范围查询有一些例外)。 排序中的字段顺序确实会影响索引选择。如果您的sort()
条件与索引顺序不匹配,则必须在使用索引后重新排序结果数据(如果发生这种情况,您应该在explain输出中看到scanAndOrder:true
。)
值得注意的是MongoDB只会使用one index per query($or
s除外)。
因此,如果您尝试优化查询:
db.col.find({category:'A'}).sort({updated: -1, rating: -1})
您需要在索引中包含所有三个字段:
db.col.ensureIndex({category: 1, updated: -1, rating: -1})
仅供参考,如果您想强制某个特定查询使用索引(通常不需要或不推荐),您可以尝试使用hint()
选项。
答案 1 :(得分:1)
这是事实,但由于您要对复合索引进行排序,因此您有两层排序。
正如您所注意到,当索引的第一个字段与其工作的第一个字段匹配并且看到索引时。但是,当以相反的方式工作时却没有。
因此,您自己的观察需要保留的顺序是从头到尾的字段查询顺序。 mongo分析器有时可以在字段中移动以匹配索引,但通常只会尝试匹配第一个字段,如果不能,则会跳过它。
答案 2 :(得分:0)
尝试此代码,它将首先根据名称对数据进行排序,然后保留'名称'在密钥持有人中,它将排序'过滤'
var cursor = db.collection('vc').find({ "name" : { $in: [ /cpu/, /memo/ ] } }, { _id: 0, }).sort( { "name":1 , "filter": 1 } );