具有投影或限制的mongodb内存排序

时间:2017-06-29 00:23:34

标签: mongodb sorting

我正在运行一个针对MongoDB的查询(在我的情况下为3.2),并且我得到了:

OperationFailed: Sort operation used more than the maximum 33554432 bytes of RAM.

我知道我可以使用索引来避免这种情况。在我的情况下,这是一个我很少运行的操作,因此索引的开销没有意义(如果此操作需要很长时间并消耗大量资源,那也没关系)。我很确定我最终会使用allowDiskUse聚合来解决这个问题,但我对某些事感到好奇。

我很好奇是否使用投影可以减少内存中排序所需的内存占用量。同样地,我想知道limit()是否可以减少这种占用空间(因为排序只需要保留内存中的顶部/底部N)。

2 个答案:

答案 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