我正在运行一个针对MongoDB的查询(在我的情况下为3.2),并且我得到了:
OperationFailed: Sort operation used more than the maximum 33554432 bytes of RAM.
我知道我可以使用索引来避免这种情况。在我的情况下,这是一个我很少运行的操作,因此索引的开销没有意义(如果此操作需要很长时间并消耗大量资源,那也没关系)。我很确定我最终会使用allowDiskUse
聚合来解决这个问题,但我对某些事感到好奇。
我很好奇是否使用投影可以减少内存中排序所需的内存占用量。同样地,我想知道limit()
是否可以减少这种占用空间(因为排序只需要保留内存中的顶部/底部N)。
答案 0 :(得分:1)
如果您的集合未编入索引,则投影将无法帮助您回避内存中的排序32 MB限制。另一方面,如果结果集的大小小于32 MB,find()
可以帮助您。
注意此答案仅涉及常规$match
方法,而不涉及相应的$sort
+ $limit
+ {"a": <a short string>, "b": <a large 10 MB value>}
聚合阶段。
Interaction with Projection文档提及:
当一组结果都被排序和预测时,MongoDB查询引擎将始终首先应用排序。
可以使用explain() method显示。例如,考虑一个包含以下形式的文档的无索引集合:
explain()
投影输出排序的> db.coll.explain().find({},{a:1}).sort({a:1})
...
"winningPlan": {
"stage": "PROJECTION",
"transformBy": {
"a": 1
},
"inputStage": {
"stage": "SORT",
"sortPattern": {
"a": 1
},
"inputStage": {
"stage": "SORT_KEY_GENERATOR",
"inputStage": {
"stage": "COLLSCAN",
"direction": "forward"
}
}
}
},
...
结果:
explain()
从COLLSCAN -> SORT -> PROJECTION
输出中,查询的各个阶段按以下顺序排列:
> db.coll.find({},{a:1}).sort({a:1})
Error: error: {
"ok": 0,
"errmsg": "Executor error during find command: OperationFailed: Sort operation used more than the maximum 33554432 bytes of RAM. Add an index, or specify a smaller limit.",
"code": 96,
"codeName": "OperationFailed"
}
这意味着当结果集大小超过32 MB时,投影将无法为您提供帮助。
运行查询导致预期的失败:
limit()
Limit results文档提及:
如果MongoDB无法通过索引扫描获得排序顺序,那么MongoDB使用top-k排序算法。此算法缓冲底层索引或集合访问到目前为止看到的前k个结果(或最后一个,具体取决于排序顺序)。如果在任何时候这些k结果的内存占用超过32兆字节,则查询将失败。
仅当要排序的总结果集仍低于32 MB时,`find({}, <projection>).limit(3).sort(...)`
才有助于此。
例如(使用上面每个文档10 MB的例子),执行
find({}, <projection>).limit(4).sort(...)
将起作用,因为需要排序的总大小为3x10 MB == 30 MB。
然而,做
{{1}}
将失败,因为结果集将包含4x10 MB == 40 MB。在两种情况下,投影都无关紧要,只需要对结果集的总大小进行排序。
请注意,使用投影不会影响查询的内存使用情况。只需要排序的结果集的大小很重要。
答案 1 :(得分:0)
我通过为排序参数创建索引解决了这个问题。 例如:
db.collection.find({ .... }).projection({...}).sort({ code: 1, name: 1 });
db.collection.createIndex({ code: 1, name: 1 }, collation: { locale: 'en'})
这样可以避免超过排序的内存限制(32mb),但是如果你的case每个条目文档都很大,你可以增加这个限制。
db.adminCommand({setParameter: 1, internalQueryExecMaxBlockingSortBytes: 33554432}) // 32mb