实际上,这个故事有两面,应用程序和服务器。
在应用程序中,第二个速度将更快。应用程序不必反序列化BSON文档(CPU密集型),然后存储不需要的数据哈希(内存密集型)。
在服务器上,MongoDB可以发送更多的数据,允许在执行
getMore
操作之前对每个游标进行更多次迭代,从而提高性能。不仅如此,你当然会发送更少的数据。
getMore
操作本身实际上是资源密集型的,无论是对内存还是CPU都是一种节省。
至于服务器内部,投影的成本很小,但比把所有内容都传输过去的成本要小。
编辑
正如其他人所说,MongoDB实际上使用投影来操纵结果集,因此两个查询之间将具有相同的工作集。
编辑
这是关于投影索引使用的结果:
> db.g.insert({a:1,b:1,c:1,d:1})
> db.g.ensureIndex({ a:1,b:1,c:1 })
> db.g.find({}, {a:0,b:0,c:0}).explain()
{
"cursor" : "BasicCursor",
"nscanned" : 3,
"nscannedObjects" : 3,
"n" : 3,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
> db.g.find({}, {a:1,b:1,c:1}).explain()
{
"cursor" : "BasicCursor",
"nscanned" : 3,
"nscannedObjects" : 3,
"n" : 3,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
这也是不使用投影的结果:
> db.g.find({}).explain()
{
"cursor" : "BasicCursor",
"nscanned" : 3,
"nscannedObjects" : 3,
"n" : 3,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
正如您所看到的,milis
表示文档上花费的时间实际上在两者之间是相同的:0
。因此,解释不是衡量这个的好方法。
另一个编辑
除了 _id 外,不包括其他字段不会使覆盖索引生效:
> db.g.find({}, {a:1,b:1,c:1,_id:0}).explain()
{
"cursor" : "BasicCursor",
"nscanned" : 3,
"nscannedObjects" : 3,
"n" : 3,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
又一次编辑
并且有300K行:
> db.g.find({}, {a:1,b:1,c:1}).explain()
{
"cursor" : "BasicCursor",
"nscanned" : 300003,
"nscannedObjects" : 300003,
"n" : 300003,
"millis" : 95,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
> db.g.find({}).explain()
{
"cursor" : "BasicCursor",
"nscanned" : 300003,
"nscannedObjects" : 300003,
"n" : 300003,
"millis" : 85,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
所以说,在一个庞大的结果集上进行投影操作确实更加耗费资源,但请记住这是在30万行数据上进行的投影操作……我是说,这有点离谱吧?谁会在理智的情况下这么做呢?因此,这部分争论实际上并不存在。无论如何,在我的硬件上,差异只有10毫秒,几乎只是你查询时间的1/10,因此投影操作并不是你的问题。
我还应该指出,--cpu
标志将不能给你想要的结果,首先它实际上涉及写锁,其次你正在进行读取操作。