首页 > 解决方案 > 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)
        }
    })

再一次,我已经在这个问题上小心翼翼了一段时间。解决问题会很棒,但更好地理解问题也很棒,谢谢您的帮助!

标签: mongodbsortingmongooseaggregation-framework

解决方案


查询执行器无法在第二阶段使用不同的索引。MongoDB 索引将键值映射到数据文件中文档的位置。一旦$match阶段完成,文档就在管道中,因此无法进一步使用索引。

但是,如果您在查询计划器上创建复合索引,{platform_number:1, date:-1}则可以将$match$sort阶段组合成一个不需要阻塞排序的阶段,这将大大提高此管道的性能。


推荐阅读