mongodb - Mongoose 聚合管道:在 MongoDB 中排序索引日期很慢
问题描述
我在我的应用程序上处理这个错误已经有一段时间了,希望有人能帮我找出这个聚合查询的错误。
我正在使用运行 MongoDB shell 版本 v4.2.8 的 docker 容器。该应用程序使用 Express.js 后端和 Mongoose 中间件与数据库交互。
我想创建一个聚合管道,它首先与一个名为“platform_number”的索引字段匹配。然后我们按索引字段“日期”(存储为 ISODate 类型)对其进行排序。剩余的管道似乎不会影响性能,它只是一些预测和过滤。
{$sort: {date: -1}}
尽管只返回了大约 250 个文档,但仍会成为整个聚合的瓶颈。我确实有一个名为“cycle_number”的未索引键,它与“日期”字段直接相关。替换{date: -1}
为{cycle_number: -1}
加快查询速度,但随后出现内存不足错误。排序在 Ram 上有一个最大 100MB 的上限,这种排序在 250 个文档时失败。
一个可能的解决方案是包含附加选项{ "allowDiskUse": true }
。但在此之前,我想知道为什么“日期”一开始就没有正确排序。另一种选择是索引'cycle_number',但同样,为什么'date'会举手?
下面提供了聚合管道。首先是匹配,然后是排序,依此类推。我很乐意解释其他函数在做什么,但是当我将它们注释掉时,它们并没有太大区别。
let agg = [ {$match: {platform_number: platform_number}} ] // indexed number
agg.push({$sort: {date: -1}}) // date is indexed in decending order
if (xaxis && yaxis) {
agg.push(helper.drop_missing_bgc_keys([xaxis, yaxis]))
agg.push(helper.reduce_bgc_meas([xaxis, yaxis]))
}
const query = Profile.aggregate(agg)
query.exec(function (err, profiles) {
if (err) return next(err)
if (profiles.length === 0) { res.send('platform not found') }
else {
res.json(profiles)
}
})
再一次,我已经在这个问题上小心翼翼了一段时间。解决问题会很棒,但更好地理解问题也很棒,谢谢您的帮助!
解决方案
查询执行器无法在第二阶段使用不同的索引。MongoDB 索引将键值映射到数据文件中文档的位置。一旦$match
阶段完成,文档就在管道中,因此无法进一步使用索引。
但是,如果您在查询计划器上创建复合索引,{platform_number:1, date:-1}
则可以将$match
和$sort
阶段组合成一个不需要阻塞排序的阶段,这将大大提高此管道的性能。
推荐阅读
- firebase - Firebase 云消息传递为已取消订阅的令牌返回 200 OK
- verilog - 如何在冒号两侧使用 % 进行 Verilog 变量部分选择?
- semantic-ui - 模态全屏向左对齐
- r - 如何使用三个不同数据帧的变量执行 PCA 并对它们进行颜色区分?
- android - 基于应用状态的 Firebase 推送通知
- camera - 通过 gpio 引脚将相机连接到树莓派
- javascript - 在本机反应中使用 onPress 调用两个函数
- sql - 数据库锁定
- angular - Angular Material:可以在 Textarea 中进行键盘导航,但会阻止所有其他键盘事件
- hibernate - 在 Hibernate 中加入 + 将结果发送到客户端应用程序