Pymongo执行sort操作超出33.5MB内存上限该如何解决
问题根因
- MongoDB针对无索引字段执行
sort操作时,会将全部匹配结果加载到内存完成排序,默认排序内存上限为32MB(即报错中的33554432字节),你匹配的数据集过大,排序时超出阈值触发错误96。 - 你修改为逐个遍历的方案没有生效,是因为触发超限的操作不是后续的列表转换/遍历步骤,而是代码前半段两次调用
sort取时间首尾的逻辑,这两步已经触发了无索引内存排序,在执行列表转换前就已经抛出错误。 - 原代码还存在冗余查询问题:对同一个
find返回的Cursor多次调用sort会触发多次数据库查询,相当于你重复拉取了3次匹配的数据集,资源消耗极高。
解决方案
方案1:给time字段加索引(最推荐)
给排序字段加索引后,排序逻辑会直接走索引无需内存排序,既没有32MB限制,查询性能也会大幅提升,执行一次索引创建即可:
# 仅需执行一次创建索引,后续所有针对time字段的排序都会自动走索引 mongo_collection.create_index("time")
索引创建完成后可以优化你的查询逻辑,仅查询一次即可同时拿到全部数据和时间区间首尾值:
import datetime search_query = {"time" : {"$lte" : datetime.datetime.now()}} # 单次排序查询所有结果 search_result = mongo_collection.find(search_query).sort("time", 1) list_search_result = list(search_result) # 直接在Python层的列表取首尾时间,无需多次查询数据库 oldest_time = list_search_result[0]["time"] latest_time = list_search_result[-1]["time"]
方案2:临时调整MongoDB排序内存上限(不推荐)
如果暂时无法创建索引,可以临时调高MongoDB服务端的排序内存阈值,需要在MongoDB Shell中执行以下命令:
# 将排序内存上限调整为128MB,可根据实际需求调整大小 db.adminCommand({setParameter:1, internalQueryExecMaxBlockingSortBytes: 134217728})
该方案为临时 workaround,调大阈值会占用更多服务端内存,大查询可能影响同实例下的其他业务,仅建议临时调试使用。
方案3:使用聚合查询开启磁盘排序
如果既无法加索引也不想修改数据库配置,可以使用聚合查询的allowDiskUse参数,允许排序时将临时数据落盘,突破内存排序的32MB限制:
import datetime pipeline = [ {"$match": {"time" : {"$lte" : datetime.datetime.now()}}}, {"$sort": {"time": 1}} ] # 开启磁盘使用权限,避免内存排序超限 search_result = mongo_collection.aggregate(pipeline, allowDiskUse=True) list_search_result = list(search_result) oldest_time = list_search_result[0]["time"] latest_time = list_search_result[-1]["time"]
该方案不需要修改数据库配置,也不用加索引,但排序性能会因为磁盘IO有所下降,适合临时查询场景。
内容的提问来源于stack exchange,提问作者geekygeek
相关产品推荐
相关产品推荐

