在MongoDB中获取文档子集的效果如何?

Ale*_*kiy 3 performance mongodb

如果我们有一个集合photos,每个条目都是一个大文档,其中包含有关照片的所有信息,包括视图详细信息和详细的upvotes/downvotes.

{
_id:ObjectId('...'),
title:'...',
location:'...',
views:[
    {...},
    {...},
    ...
    ],
upvotes:[
    {...},
    {...},
    ...
    ],
downvotes:[
    {...},
    {...},
    ...
    ],
}
Run Code Online (Sandbox Code Playgroud)

哪个查询可以更快地工作并且更有效(内存,CPU使用率):

db.photos.find().limit(100)
Run Code Online (Sandbox Code Playgroud)

要么

db.photos.find({}, {views:0,upvotes:0,downvotes:0}).limit(100)
Run Code Online (Sandbox Code Playgroud)

Sam*_*aye 5

这个故事实际上有两个方面,即应用程序和服务器.

在应用程序中,第二个将更快.应用程序不必对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" : {

        }
}
Run Code Online (Sandbox Code Playgroud)

这也是不使用投影的结果:

> db.g.find({}).explain()
{
        "cursor" : "BasicCursor",
        "nscanned" : 3,
        "nscannedObjects" : 3,
        "n" : 3,
        "millis" : 0,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "isMultiKey" : false,
        "indexOnly" : false,
        "indexBounds" : {

        }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的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" : {

        }
}
Run Code Online (Sandbox Code Playgroud)

又一个编辑

并且有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" : {

        }
}
Run Code Online (Sandbox Code Playgroud)

所以投影在一个巨大的结果集上更加昂贵,但记得那是300K行的投影...我的意思是WTF?在他们正确的思想中,谁会这样做?所以这部分论证并不存在.无论哪种方式,我的硬件上的差异就像是10毫秒,几乎只有你查询的十分之一,因为这样的投影不是你的问题.

我还应该注意,该--cpu标志不会给你你想要的东西,对于初学者来说,它实际上是关注写锁定,然后是你的读取.