我有一个数据模式,其中包含分配给实体的许多更新(每个实体数十万个以上)。我用每个实体的单个顶级文档以及每个实体下的一组更新来表示这一点。这些顶级文档的架构如下所示:
{
"entity_id": "uuid",
"updates": [
{ "timestamp": Date(...), "value": 10 },
{ "timestamp": Date(...), "value": 11 }
]
}
我正在尝试创建一个查询,该查询返回过去 n 小时内收到更新的实体数量。 updates
数组中的所有更新都保证根据我的应用程序更新它们的方式进行排序。我创建了以下聚合来执行此操作:
db.getCollection('updates').aggregate([
{"$project": {last_update: {"$arrayElemAt": ["$updates", -1]}}},
{"$replaceRoot": {newRoot: "$last_update"}},
{"$match": {timestamp: {"$gte": new Date(...)}}},
{"$count": "count"}
])
出于某种我不明白的原因,我刚刚粘贴的查询需要花费大量时间才能完成。事实上,它耗尽了我使用的客户端上的 15 秒超时。
从时间复杂度的角度来看,这个查询看起来非常便宜(这是我设计这个模式的方式的一部分)。它看起来与集合中的顶级文档总数呈线性关系,然后过滤掉集合中的顶级文档总数,其中不到 10,000 个。
令人困惑的部分是,它似乎并不是昂贵的 $project
步骤。如果我单独运行该查询,查询将在 2 秒内完成。但是,仅添加 $match
步骤就会导致超时,并显示运行数据库的服务器上存在大量 CPU 和 IO 使用情况。我最好的猜测是,由于某种原因,它正在对完整更新数组执行一些操作,这是没有意义的,因为第一步明确地将其限制为仅最后一个元素。
有什么方法可以提高此聚合的性能吗?即使数组访问模式本高度效,将所有更新都放在一个数组中是否会导致 Mongo 无法创建最佳查询?
按照我之前的做法并将每个更新存储为标有其父实体 ID 的顶级文档会更好吗?这就是我之前所做的,但性能非常糟糕,我想我应该尝试这个模式来努力改进它。到目前为止,这种经历与我的期望/希望相反。
最佳答案
使用索引,它将提高查询的性能。
https://docs.mongodb.com/manual/indexes/
为此,请使用 mongo compass 检查哪个索引最常用,然后将它们一一索引以提高其性能。
之后,获取您最终需要的字段,并进行聚合投影。
我希望这可以解决您的问题。但我建议先建立索引。在获取大量数据的情况下,这是一个巨大的优势。
关于mongodb - 如何改善使用数组聚合时糟糕的 MongoDB 查询性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57851093/