Ali*_*eza 17 mongodb projection
从MongoDB
文档中提到:
当您只需要文档中的一部分字段时,您可以通过只返回您需要的字段来获得更好的性能
过滤字段如何影响性能?性能是否与通过网络传输的数据大小有关?或将保存在内存中的数据大小?这种性能究竟是如何提高的?文档中提到的这种性能是什么?
我的 MongoDB 查询速度很慢。返回子集是否会影响我的慢查询(我在该字段上有复合索引)?
Ste*_*nie 23
默认情况下,查询返回匹配文档中的所有字段。如果您需要所有字段,返回完整文档将比让服务器使用投影标准操作结果集更有效。
但是,使用投影来限制从查询结果返回的字段可以通过以下方式提高性能:
当使用投影删除未使用的字段时,MongoDB 服务器必须将每个完整文档提取到内存中(如果它还没有)并过滤结果以返回。这种投影的使用不会减少 MongoDB 服务器上的内存使用量或工作集,但可以根据您的数据模型和投影的字段为查询结果节省大量网络带宽。
覆盖查询是一种特殊情况,查询结果中的所有请求字段都包含在所使用的索引中,因此服务器不必获取完整文档。覆盖查询可以提高性能(通过避免获取文档)和内存使用(如果其他查询不需要获取相同的文档)。
为了通过mongo
shell进行演示,假设您有一个如下所示的文档:
db.data.insert({
a: 'webscale',
b: new Array(10*1024*1024).join('z')
})
Run Code Online (Sandbox Code Playgroud)
该字段b
可能代表一组值(或者在这种情况下是一个很长的字符串)。
接下来,创建一个索引,{a:1}
该索引是您的用例查询的常用字段:
db.data.createIndex({a:1})
Run Code Online (Sandbox Code Playgroud)
一个findOne()
没有投影条件的简单返回一个大约 10MB 的查询结果:
> bsonsize(db.data.findOne({}))
10485805
Run Code Online (Sandbox Code Playgroud)
添加投影{a:1}
会将输出限制为字段a
和文档_id
(默认情况下包括在内)。MongoDB 服务器仍然在操纵一个 10MB 的文档来选择两个字段,但查询结果现在只有 33 个字节:
> bsonsize(db.data.findOne({}, {a:1}))
33
Run Code Online (Sandbox Code Playgroud)
此查询未包含在内,因为必须提取完整文档才能发现该_id
值。该_id
字段默认包含在查询结果中,因为它是文档的唯一标识符,但_id
除非明确添加,否则不会包含在二级索引中。
结果中的totalDocsExamined
和totalKeysExamined
指标explain()
将显示检查了多少文档和索引键:
> db.data.find(
{a:'webscale'},
{a:1}
).explain('executionStats').executionStats.totalDocsExamined
> 1
Run Code Online (Sandbox Code Playgroud)
可以使用投影改进此查询以排除_id
字段并仅使用{a:1}
索引实现覆盖查询。覆盖的查询不再需要将大约 10MB 的文档提取到内存中,因此在网络和内存使用方面都很高效:
> db.data.find(
{a:'webscale'},
{a:1, _id:0}
).explain('executionStats').executionStats.totalDocsExamined
0
> bsonsize(db.data.findOne( {a:'webscale'},{a:1, _id:0}))
21
Run Code Online (Sandbox Code Playgroud)
我的 MongoDB 查询速度很慢。返回子集是否会影响我的慢查询(我在该字段上有复合索引)?
如果没有特定查询的上下文、示例文档和完整的解释输出,这是无法回答的。但是,您可以在自己的环境中为相同的查询运行一些基准测试,使用和不使用投影来比较结果。如果您的投影显着增加了整个查询执行时间(处理和传输结果)的开销,这可能强烈暗示您的数据模型可以改进。
如果不清楚为什么查询很慢,最好发布一个包含具体细节的新问题进行调查。