[英]How can I optimize this query in mongo db?
这是查询:
const tags = await mongo
.collection("positive")
.aggregate<{ word: string; count: number }>([
{
$lookup: {
from: "search_history",
localField: "search_id",
foreignField: "search_id",
as: "history",
pipeline: [
{
$match: {
created_at: { $gt: prevSunday.toISOString() },
},
},
{
$group: {
_id: "$url",
},
},
],
},
},
{
$match: {
history: { $ne: [] },
},
},
{
$group: {
_id: "$word",
url: {
$addToSet: "$history._id",
},
},
},
{
$project: {
_id: 0,
word: "$_id",
count: {
$size: {
$reduce: {
input: "$url",
initialValue: [],
in: {
$concatArrays: ["$$value", "$$this"],
},
},
},
},
},
},
{
$sort: {
count: -1,
},
},
{
$limit: 50,
},
])
.toArray();
我想我需要一个索引,但不确定如何或在哪里添加。
在我们确认该方法本身是合理的满足所需的应用程序逻辑之后,也许应该重新审视该操作的性能。
在性能方面,如果目的是处理每个文档,则无法提高positive
收集的效率。 根据定义,处理所有文档需要完整的集合扫描。
为了有效地支持search_history
集合上的$lookup
,您可能希望确认{ search_id: 1, created_at: 1, url: 1 }
上的索引存在。 提供.explain("allPlansExecution")
output 将使我们能够更好地了解当前的性能特征。
更新问题以包含有关架构和聚合目的的详细信息对于理解整体情况非常有帮助。 仅查看聚合,它似乎正在执行以下操作:
positive
集合中的每个文档,添加一个名为history
的新字段。search_history
集合的url
值的列表,其中相应的文档具有匹配的search_id
值并且是在上created_at
之后创建的。history
字段具有至少一个条目的文档。word
将结果组合在一起。 这里使用了$addToSet
运算符,但它可能会生成一个 arrays 数组,而不是去重复的url
数组。url
的数量,并按按该大小降序排序的word
返回前50
结果。这是你想要的吗? 特别是以下方面可能值得确认:
positive
集合中的每个文档? 可能是这种情况,但如果没有任何模式/用例上下文,就无法判断。url
的尺寸计算是否正确? 在为$group
执行$addToSet
而不是为后续的$project
使用$reduce
时,您似乎可能需要使用$map
。最好的办法是限制传递到每个阶段的文档数量。 只有在匹配时,mongo 才会在聚合中使用索引,最大使用 1 个索引。
所以最好的办法是在一个非常严格的索引字段上进行匹配。
此外,请注意$limit
、 $skip
和$sample
不是万能的,因为它们仍然会扫描整个集合。
一种有效限制第一阶段选择的文档数量的方法是使用“分页”。 你可以让它像这样工作:
每 X 请求一次
每一个请求
used
的密钥和nbChunks
获取当前要扫描的块id:${used%nbChunks}
和id:${(used%nbChunks)+1}
$match
进行聚合_id:{$gte: ObjectId(id0), $lt: ObjectId(id1)}) }
used
增量,如果used > X
则更新块进一步优化
如果使用 redis,请在每个键后面加上${cluster.worker.id}:
以避免热键。
笔记
$lt
$match
是第一阶段,_id 是一个被索引的字段,这个第一阶段非常快,并且限制了扫描的最大 Y 个文档。希望它有所帮助=)如果需要,请务必询问更多=)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.