Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb$expr查询速度非常慢_Mongodb_Aggregation Framework_Query Performance - Fatal编程技术网

Mongodb$expr查询速度非常慢

Mongodb$expr查询速度非常慢,mongodb,aggregation-framework,query-performance,Mongodb,Aggregation Framework,Query Performance,我的开发环境中有一个Mongo4.2.0实例,它只包含300个条目 我用一些日期字段构建了一些基本的队列处理 为了得到一个应该更新的文档,我使用了下面的$expr查询,它在imho中运行得非常慢 db.collection("myupdates").findOneAndUpdate({ $expr: { $and: [ { $gt: ["$shouldUpdate", "$updatedAt"] }, { $gt: ["$shouldUpdat

我的开发环境中有一个Mongo4.2.0实例,它只包含300个条目

我用一些日期字段构建了一些基本的队列处理

为了得到一个应该更新的文档,我使用了下面的$expr查询,它在imho中运行得非常慢

db.collection("myupdates").findOneAndUpdate({
    $expr: {
      $and: [
        { $gt: ["$shouldUpdate", "$updatedAt"] },
        { $gt: ["$shouldUpdate", "$isUpdatingAt"] },
        { $gt: ["$shouldUpdate", "$updateErroredAt"] },
      ]
    },
  }, {
    $set: {
      isUpdatingAt: new Date(),
    },
  });
在我的标准2019年笔记本电脑上进行预热后,此查询大约需要~120ms。我的其他简单查询只需要3毫秒

虽然用300个文档设置索引并不重要,但我当然已经尝试将它们全部设置好了。单索引到复合索引。这不起作用

它也不是
findOneAndUpdate
,与
countDocuments
相比,我的速度同样慢

这是$expr或聚合语法的正常速度吗?我做错了什么?有没有更好的方法来实现这一点?对于这个用例,我必须使用Redis吗

可能的解决办法 正如Neil Lunn在回答中指出的那样,计算条件不使用指数,应该是最后的手段

因此,我只是通过将查询拆分为两个查询来摆脱计算条件。第一个查询是获取我可以匹配的实际值。 这两个查询总计约10毫秒,比120毫秒好得多

  const shouldUpdateDateResult = await mongo.db.collection("myupdates").findOne({
    shouldUpdate: { $exists: true }
  }, {
    shouldUpdate: 1,
  });

  const shouldUpdateDate = shouldUpdateDateResult && shouldUpdateDateResult.shouldUpdate;

  const result = await mongo.db.collection("myupdates").findOneAndUpdate({
    $and: [
      { shouldUpdate: shouldUpdateDate },
      { $or: [
        { updatedAt: { $eq: null } },
        { updatedAt: { $exists: false } },
        { updatedAt: { $lte: shouldUpdateDate } }
      ] },
      { $or: [
        { isUpdatingAt: { $eq: null } },
        { isUpdatingAt: { $exists: false } },
        { isUpdatingAt: { $lte: shouldUpdateDate } }
      ] },
      { $or: [
        { updateErroredAt: { $eq: null } },
        { updateErroredAt: { $exists: false } },
        { updateErroredAt: { $lte: shouldUpdateDate } }
      ] },
    ],
  }, {
    $set: {
      isUpdatingAt: new Date(),
    },
  });

这背后的整个想法是一个可供多个工作人员使用的处理队列。

当然它很慢。计算条件不能使用索引,因此实际上应该是最后的手段,而不是在任何规模的生产实现中需要依赖的东西。顺便说一句,这不仅仅是MongoDB的事情。你做错了吗?对你该怎么办?如果没有更好的解释,我们真的不知道为什么你认为你想做这种更新,以及总体目的是什么。只有当你解释了这一点,你才能得到关于更好设计的有意义的反馈。不确定您是否选择了标记或它是否是“自动建议的”(问题编辑器通常会这样做),但最初应用于问题的
expr
标记实际上是用于完全不同的用途。关于该主题的更多信息,诸如完整集合扫描和不使用索引等重要内容确实在
$expr
文档中明显缺失。在非常相似的
$where
子句上有一些警告,但即使是这样,它似乎也比以前有所缓和。这很有帮助。我不知道计算的条件不使用索引,但如果我仔细想想,它完全有道理。这应该在Mongo文档顶部用红色大字注明。我已经编辑了我的问题,并用一个可能的解决方案对其进行了更新,尽管我想还有一些优化的空间。整个过程应该是一个可供多个工作人员使用的处理队列。当然它很慢。计算条件不能使用索引,因此实际上应该是最后的手段,而不是在任何规模的生产实现中需要依赖的东西。顺便说一句,这不仅仅是MongoDB的事情。你做错了吗?对你该怎么办?如果没有更好的解释,我们真的不知道为什么你认为你想做这种更新,以及总体目的是什么。只有当你解释了这一点,你才能得到关于更好设计的有意义的反馈。不确定您是否选择了标记或它是否是“自动建议的”(问题编辑器通常会这样做),但最初应用于问题的
expr
标记实际上是用于完全不同的用途。关于该主题的更多信息,诸如完整集合扫描和不使用索引等重要内容确实在
$expr
文档中明显缺失。在非常相似的
$where
子句上有一些警告,但即使是这样,它似乎也比以前有所缓和。这很有帮助。我不知道计算的条件不使用索引,但如果我仔细想想,它完全有道理。这应该在Mongo文档顶部用红色大字注明。我已经编辑了我的问题,并用一个可能的解决方案对其进行了更新,尽管我想还有一些优化的空间。整个过程应该是一个可供多个工作人员使用的处理队列。