MongoDB查询响应太慢

时间:2020-08-27 06:24:58

标签: mongodb mgo

我正在研究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},那么它的运行速度很快,但是这种排序会花费太多时间。

如何以及如何做才能缩短响应时间。

1 个答案:

答案 0 :(得分:0)

该聚合正在做什么:

  1. 从collection1中检索所有文档
  2. 对于collection1中的每个文档,在collection2中找到一个文档
  3. 对于collection1中的每个文档,在collection3中找到一个文档
  4. 对于collection1中的每个文档,在日志中找到所有已实现的文档
  5. 对于collection1中的每个文档,对从日志中检索到的文档进行内存排序
  6. 执行内存排序来排序文档
  7. 保留其中2份文档,其余部分丢弃

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

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

如果可以安全地假设logs中的每个文档都包含一个映射回log_id的{​​{1}},则可以:

  • collection1上创建索引
  • 在日志收集上开始聚合
  • {logged_on:1, log_id:1}排序
  • 项目logged_on: 1(这使聚合的第一部分完全由上述索引覆盖)
  • {logged_on:1, log_id:1, _id:0}分组,取log_id的{​​{1}}值
  • $first排序(分组不影响排序)
  • 根据需要跳过和限制
  • 通过logged_on与本地logged_on: 1外部collection1进行查找
  • replaceRoot,其中newRoot是查找的文档
  • 执行您正在使用的现有管道阶段-这次,它们将仅针对要返回的2个文档进行获取/排序。