Mongo聚合查询优化

时间:2020-06-14 04:12:23

标签: node.js mongodb mongoose

我有一个收藏有270万个文档的收藏。我需要根据某些条件获取一些数据。 问题是我的查询正在扫描将近100万个文档,仅返回5个文档。

请帮助我优化此查询以及应创建哪个索引以最小化文档扫描。

这是我的查询

{
"aggregate": "posts",
    "pipeline": [
      {
        "$match": {
          "status": "A",
          "hashtagIds": {
            "$oid": "5d9c866d9f733d2359a3e0e0"
          },
          "mediaLocation.mediaType": 2,
          "mediaLocation.thumbNailPath": {
            "$exists": true,
            "$ne": null
          }
        }
      },
      {
        "$lookup": {
          "from": "users",
          "localField": "userId",
          "foreignField": "_id",
          "as": "ownerData"
        }
      },
      {
        "$unwind": {
          "path": "$ownerData",
          "preserveNullAndEmptyArrays": true
        }
      },
      {
        "$sort": {
          "viewsCount": -1
        }
      },
      {
        "$limit": 5
      }
    ]
}

1 个答案:

答案 0 :(得分:0)

更好的索引和阶段的重新排序应该会很有帮助。

索引

当前管道使用

上的索引
{
  "mediaLocation.mediaType": 1,
  status: 1,
  genter: 1
}

虽然此索引确实支持4个查询字段中的2个,但它不支持排序操作,所以查询执行程序必须将所有匹配的文档加载到内存中并对其进行排序,以确定哪个5个字段优先。

通过包含所有查询字段和排序字段的索引,可以更好地解决此查询。请注意,相等匹配的字段位于索引规范中的排序字段之前:

{
  "mediaLocation.mediaType": 1,
  status: 1,
  hashtagIds: 1,
  viewsCount: -1,
  "mediaLocation.thumbNailPath"
}

阶段订单

在现有管道中:

  • $ match:检索所有856k匹配的文档
  • $ lookup:针对users集合执行了856k查询
  • $ unwind:将856k数组字段转换为对象
  • $ sort:内存中的856k文档
  • $ limit:返回前5个文档

对字段进行简单的重新排序以及上面的索引,将显着提高性能:

  • $ match:
  • $ sort:
  • $ limit:
    如果存在上述索引,则首先放置这些阶段可以使查询计划者将这3个阶段组合为一个,使用索引以预先排序的顺序标识字段,并在找到5个匹配项时立即停止。合并后的阶段将读取5个文档以及索引键
  • $ lookup:在用户集合中执行5个查询
  • $ unwind:将5个数组转换为对象