使用聚合操作时出现Mongo错误:排序超出内存限制

45

当我使用聚合排序时,我遇到了mongo错误超出内存限制,错误代码为16819

我正在使用mongo 2.6版本。

查询如下:

db.BASE_TABLE_CREATION_ExecuteHiveScript_26_V0.aggregate([
     { "$project" : { "visitor_localdate" : 1 , "_id" : 0}}, 
     { "$sort" : { "visitor_localdate" : -1}}
])
9个回答

55

默认情况下,MongoDB中的聚合是在内存中进行的,并且管道阶段的内存限制为100 Mb。看起来您已经超过了此阈值。为了处理大型数据集,您应该启用聚合管道阶段将数据写入临时文件。使用 allowDiskUse 选项:

db.BASE_TABLE_CREATION_ExecuteHiveScript_26_V0.aggregate([
    { "$project" : { "visitor_localdate" : 1 , "_id" : 0}},
    { "$sort" : { "visitor_localdate" : -1}}
], { "allowDiskUse" : true })

嗨Sergey,我试过了。它没用。。我得到了同样的异常。 - acube
@acube 确保你真的尝试过这个。如果你查看mongodb的github源代码,你会发现MongoDB错误代码,而16819代码有非常清晰的解释注释和解决步骤:排序超出了内存限制字节,但没有选择外部排序。操作中止。传递allowDiskUse:true以选择加入。 - Sergey Berezovskiy
6
使用Mongoose时,使用以下代码: db.BASE_TABLE.aggregate([]).allowDiskUse(true); 该代码用于允许在聚合查询中使用磁盘空间。 - kheengz
请见Sonia下面的答案。虽然这样做是可行的,但如果您可以将排序提前到管道中,以便MongoDb可以利用索引,则查询将不需要在第一次内存排序。这将使它在大型数据集上更具性能。 - Kip
实际解决方案是Sonia的回答-https://dev59.com/oF8d5IYBdhLWcg3w1VI1#55491963 - Avraham Shalev

28
如果您正在使用聚合查询,请在排序字段上放置索引,然后使用排序操作符。
注意: 将排序操作符放置在管道的开头或者在$project、$unwind和$group聚合操作符之前。如果$project、$unwind或者$group出现在$sort操作之前,$sort将无法使用任何索引。

https://docs.mongodb.com/manual/reference/operator/aggregation/sort


谢谢您的提问,另一个问题是针对大型数据集,是否可以使用流和暂停恢复您的流。 - Ramakant Singh
2
谢谢你的提醒,我遇到了运行排序之前运行取消操作的确切问题,并一直收到此错误。将它们交换位置后问题得到解决! - soapycat
哇,这是一个很棒的见解。谢谢。 - Manny
1
这是实际解决方案。allowDiskUse只是一个解决方法。 - Vincz777
链接修复:https://www.mongodb.com/docs/manual/reference/operator/aggregation/sort - dheeraj9499

22

在聚合管道后使用 { allowDiskUse: true },如下所示:

db.collectionOrView.aggregate([], { allowDiskUse: true });

5
您不需要使用聚合操作。请使用以下查询:
db.BASE_TABLE_CREATION_ExecuteHiveScript_26_V0.find({}, { "_id" : 0, "visitor_localdate" : 1 }).sort({ "visitor_localdate" : -1 })

并在 visitor_localdate 上建立索引。这比聚合更简单、更快速。


2
我遇到了这个错误:-“errmsg”:“在查找命令期间发生执行器错误:OperationFailed:排序操作使用了超过最大33554432字节的RAM。添加索引或指定较小的限制。” - ak3191

4
为了解决这个问题,在查询中启用allowDiskUse选项:
解决方案:
参考:内存限制
在MongoDB中,in-sort的最大内存限制为100M,如果你执行更大的排序,需要使用allowDiskUse选项将数据写入临时文件进行排序。
将allowDiskUse选项添加到查询中:
db.bigdata.aggregate(
[
 {$group : {_id : "$range", total : { $sum : 1 }}},
 {$sort : {total : -1}}
],
 {allowDiskUse: true}
);

4
在我的场景中,我通过为排序列添加索引来解决了这个问题。

3

对于Mongoose

await Model.aggregate([{ $match: { foo: 'bar' } }]).allowDiskUse(true);

来源:https://mongoosejs.com/docs/api.html#query_Query-allowDiskUse

allowDiskUse()

如果查询需要使用磁盘,则允许MongoDB使用磁盘。当查询的数据量大于内存时,MongoDB会自动使用磁盘。

注意:如果您使用的是MongoDB版本2.6或更早版本,则不支持此选项。


2

对于那些寻找 pymongo 答案的人

并且出现 AttributeError: 'dict' object has no attribute '_txn_read_preference'

这个方法有效:

db.coll.aggregate([], allowDiskUse=True)

2
对我来说,有几个因素起到了作用:
  1. 正如已经告诉过我一样,我在我的typeorm聚合中使用了 { allowDiskUse: true }

  2. 在聚合之前,我必须放置 { $sort: {} }

    [{ $sort: {} }, ...aggregation]

最后它奏效了!

排序对我也很有帮助,但我必须按某个东西进行排序。谢谢! - Alvaro Mendez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接