【问题标题】:MongoDB aggregate with lookup and sort using associated collection fields is slowing down the query使用关联的集合字段进行查找和排序的 MongoDB 聚合正在减慢查询速度
【发布时间】:2020-02-04 12:24:32
【问题描述】:

我的 mongodb 数据库中有两个集合,如下所示:

employee_details 包含大约 330000 个文档,其中 department_id 作为部门集合的参考

departments 包含 2 个字段 _iddept_name

的集合

我已将索引添加到集合中,如下所示

db.departments.createIndex( { dept_name: 1 } )
db.employee_details.createIndex( { department_id: 1 } )
db.employee_details.createIndex( { employee_fname: 1 } )

我想通过加入两个集合来获取数据以在数据表中列出。但是当我尝试这样做时,我遇到了两个问题。

首先,当我在查找后添加排序时,查询运行需要很长时间,我在查找后添加了排序,因为我需要使用收集部门的 dept_name 进行排序。查询如下

db.getCollection("employee_details").aggregate([
  {
    $lookup: {
      from: "departments",
      localField: "department_id",
      foreignField: "_id",
      as: "Department"
    }
  },
  { $unwind: { path: "$Department", preserveNullAndEmptyArrays: true } },
  { $sort: { "Department.dept_name": 1 } },
  { $limit: 30 }
]);

第二次,当我在查找上方添加排序时,查询会变得很快,但如果我使用 dept_name 或 department_id 排序,结果会给出错误排序(排序适用于 employee_details 集合的字段)。查询如下

db.getCollection("employee_details").aggregate([
  { $unwind: { path: "$Department", preserveNullAndEmptyArrays: true } },
  { $sort: { "Department.dept_name": 1 } },
  //{ $sort: { "department_id": 1 } }, // tried this also
  { $limit: 30 },
  {
    $lookup: {
      from: "departments",
      localField: "department_id",
      foreignField: "_id",
      as: "Department"
    }
  }
]);

有人可以提供一个优化的解决方案,用于从所有相关集合中获取数据以及排序。 提前谢谢你。

【问题讨论】:

  • 您希望输出是什么样的生成的数据集的用途是什么?
  • 我在问题中提到过。考虑departments 集合中的样本数据,例如 cat1、cat2、cat3。大约有 3000000 名员工选择这 3 个部门中的任何一个。然后在问题中解释了问题。我不能在这里添加我的数据集,但有人可以用我的信息轻松创建数据集

标签: mongodb sorting limit lookup


【解决方案1】:

试试这个:

db.departments.aggregate([
  {
    $sort: {
      "dept_name": 1
    }
  },
  {
    $lookup: {
      from: "employee_details",
      localField: "_id",
      foreignField: "department_id",
      as: "Employee"
    }
  },
  {
    $unwind: "$Employee"
  },
  {
    $addFields: {
      tmp: {
        $mergeObjects: [
          {
            Department: "$$ROOT"
          },
          "$Employee"
        ]
      }
    }
  },
  {
    $project: {
      "tmp.Department.Employee": 0
    }
  },
  {
    $addFields: {
      "tmp.Department": [
        "$tmp.Department"
      ]
    }
  },
  {
    $replaceRoot: {
      newRoot: "$tmp"
    }
  },
  {
    $limit: 30
  }
])

MongoPlayground

【讨论】:

  • 这似乎是一个优化的解决方案。但是你需要在$lookup之后做$unwind$project
  • @Ajith 是的。请提供样本数据
  • 数据量很大,我不能在这里分享。我只是注意到 $unwind$project ,感谢您的回答。也期待更多答案
  • 出现错误,因为管道阶段名称无法识别:'$unset'
  • @Ajith 请再次检查。我即兴创作了样本数据
【解决方案2】:

您可以使用以下聚合:

db.getCollection("departments").aggregate([
    {
        $sort: {
            "dept_name": 1
        }
    },
    {
        $lookup: {
            from: "employee_details",
            localField: "_id",
            foreignField: "department_id",
            as: "employees"
        }
    },
    {
        $unwind: "$employees"
    },
    {
        $limit: 30
    },
    { $addFields: { "employees.department_name": "$dept_name" } },
    { $replaceRoot: { newRoot: "$employees" } }
])

这适用于 MongoDB 3.4 版,即使没有任何索引也足够快。

【讨论】:

  • @Ajith 你能试试这个解决方案,并反馈它是否工作正常和快速。
  • @Sah 非常感谢,这似乎是一个优雅的解决方案
  • @Ajith 我很高兴我们最后解决了您的问题。请不要忘记投票并将其标记为答案。
  • @Sah 还有一个问题,我在您现有的查询中添加了跳过,我发现以下观察结果如果跳过是 330000 它需要 8 秒然后跳过 = 250000 然后 5 秒。跳过 = 150000 然后 4.5 秒。跳过 = 50000 然后 1 秒。这只是一个评论,我很想知道为什么会这样。我对最坏的情况感到满意 9 秒 .. 非常感谢兄弟
  • @Ajith 似乎当跳过增加时,响应时间也会增加。我想这与 mongodb 的内部工作有关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-05
  • 1970-01-01
  • 2020-07-27
  • 1970-01-01
  • 2019-04-12
  • 2017-03-17
  • 2015-05-30
相关资源
最近更新 更多