我在MongoDb中有超过600k的记录。 我的用户架构如下所示:
{
"_id" : ObjectId,
"password" : String,
"email" : String,
"location" : Object,
"followers" : Array,
"following" : Array,
"dateCreated" : Number,
"loginCount" : Number,
"settings" : Object,
"roles" : Array,
"enabled" : Boolean,
"name" : Object
}
以下查询:
db.users.find(
{},
{
name:1,
settings:1,
email:1,
location:1
}
).skip(656784).limit(10).explain()
结果如下:
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 10,
"nscannedObjects" : 656794,
"nscanned" : 656794,
"nscannedObjectsAllPlans" : 656794,
"nscannedAllPlans" : 656794,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 5131,
"nChunkSkips" : 0,
"millis" : 1106,
"server" : "shreyance:27017",
"filterSet" : false
}
并删除投影相同的查询db.users.find().skip(656784).limit(10).explain()
结果如下:
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 10,
"nscannedObjects" : 656794,
"nscanned" : 656794,
"nscannedObjectsAllPlans" : 656794,
"nscannedAllPlans" : 656794,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 5131,
"nChunkSkips" : 0,
"millis" : 209,
"server" : "shreyance:27017",
"filterSet" : false
}
据我所知,投影总是会提高查询的性能。所以我无法理解为什么MongoDB的表现如此。有人可以解释一下吗。什么时候使用投影,什么时候不投影。以及如何在MongoDB中实现投影。
答案 0 :(得分:4)
你是正确的,投影使MongoDB 2.6.3中的跳过查询更慢。这与2.6查询计划程序跟踪为SERVER-13946的优化问题有关。
2.6查询规划器(在2.6.3中)是在投影分析之后添加SKIP(和LIMIT)阶段,因此投影被不必要地应用于在跳过此查询期间被抛出的结果。我在MongoDB 2.4.10中测试了类似的查询,nScannedObjects
等于我的limit
而不是skip + limit
返回的结果数。
有几个因素会影响您的查询效果:
1)您尚未指定任何查询条件({}
),因此此查询正在natural order进行集合扫描,而不是使用索引。
2)无法覆盖查询,因为没有投影。
3)您的skip
值非常大,为656,784。
查询计划肯定有改进的余地,但我不希望这种大小的跳过值在正常使用中是合理的。例如,如果这是一个分页应用程序查询,每页50个结果,那么skip()
值将相当于页码13,135。
答案 1 :(得分:2)
除非您的投影结果产生了“仅索引”查询,并且这意味着只有结果中“投影”的字段所有仅存在于索引中,那么您始终为查询引擎生成更多工作。
你必须考虑这个过程:
我如何匹配?在文档或索引?找到适当的主要或其他索引。
给定索引,扫描并查找内容。
现在我该返回什么?索引中的数据是全部吗?如果没有回到集合并提取文件。
这是基本过程。因此,除非其中一个阶段以任何方式“优化”,否则事情“需要更长时间”。
您需要将此视为设计“服务器引擎”并了解需要采取的步骤。考虑到你的条件都不符合在指定步骤中产生“最佳”的任何条件,你需要学习接受它。
您的“最佳”案例是仅投影字段是所选索引中的字段。但实际上,即使这样也有加载索引的开销。
因此明智地选择,并了解您编写查询的内容的约束和内存要求。这就是“优化”的全部内容。