首页 > 解决方案 > MongoDB查询响应太慢

问题描述

我正在开发一个 Golang 项目(db MongoDB)。我已经执行了以下查询,但加载数据需要太多时间。在此,我从具有多个阶段的 2 个集合中获取数据。

db.getCollection('Collection1').aggregate([
{
    "$lookup": {
        "localField": "uid",
        "from": "collection2",
        "foreignField": "_id",
        "as": "user_info"
    }
},
{
    "$unwind": "$user_info"
},
{
    "$lookup": {
        "localField": "cid",
        "from": "collection3",
        "foreignField": "_id",
        "as": "cust_info"
    }
},
{
    "$lookup": {
        "from": "logs",
        "let":  {"id": "$_id"},
        "pipeline": [
                {"$match": {"$expr": {"$eq": ["$$id", "$log_id"]}}},
                {"$sort": {"log_type": 1}}],
        "as": "logs_data"
    }
},
{
    "$sort": {"logs_data.logged_on":-1}
},
{
    "$skip": 1
},
{
    "$limit": 2
},
])

我的要求是在同一查询中添加 2 次排序:

  1. 在日志数组中"$sort": {"log_type": 1}}
  2. 对于最终结果"$sort": {"logs_data.logged_on":-1}

为此,我尝试了以下索引:

{"logged_on" : -1}
{"log_id":1, "log_type":1}

但是查询仍然需要 6-7 秒才能执行。

如果我删除"$sort": {"logs_data.logged_on":-1}它,它会运行得很快,但是这种排序会花费太多时间。

如何以及我可以做些什么来改善响应时间。

标签: mongodbmgo

解决方案


该聚合在做什么:

  1. 从 collection1 中检索所有文档
  2. 对于 collection1 中的每个文档,在 collection2 中查找单个文档
  3. 对于 collection1 中的每个文档,在 collection3 中查找单个文档
  4. 对于 collection1 中的每个文档,在日志中查找所有相关文档
  5. 对于 collection1 中的每个文档,对从日志中检索到的文档执行内存排序
  6. 执行内存排序以对文档进行排序
  7. 保留其中 2 个文件并丢弃其余文件

对于 collection1 中的每个文档,它是 3 次文档提取(加上 #4 中未知的提取次数)、2 次索引扫描和内存排序。

如果 collection1 中有大量的文档,那就是大量的工作,除了 2 个文档之外的所有文档都是浪费的。

如果可以安全地假设其中的每个文档都logs包含log_id映射回 的a collection1,那么您可以:

  • 创建一个索引{logged_on:1, log_id:1}
  • 在日志收集上启动聚合
  • 排序方式logged_on: 1
  • 项目{logged_on:1, log_id:1, _id:0}(这使得聚合的第一部分完全被上述索引覆盖)
  • 分组log_id$first取值logged_on
  • 排序依据logged_on: 1(分组分配排序)
  • 根据需要跳过和限制
  • collection1与当地log_id外籍人士一起查找_id
  • replaceRoot , newRoot 是查找的文档
  • 执行您正在使用的现有管道阶段 - 这次他们只会为您要返回的 2 个文档获取/排序。

推荐阅读