Mongodb$expr查询速度非常慢
我的开发环境中有一个Mongo4.2.0实例,它只包含300个条目 我用一些日期字段构建了一些基本的队列处理 为了得到一个应该更新的文档,我使用了下面的$expr查询,它在imho中运行得非常慢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
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文档顶部用红色大字注明。我已经编辑了我的问题,并用一个可能的解决方案对其进行了更新,尽管我想还有一些优化的空间。整个过程应该是一个可供多个工作人员使用的处理队列。