【发布时间】:2020-01-11 01:09:42
【问题描述】:
我有一个数据模式,其中包含分配给实体的许多更新(每个实体数十万+)。我用每个实体的单个顶级文档和每个实体下的一组更新来表示这一点。这些顶级文档的架构如下所示:
{
"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 标记会更好吗?这是我以前做的,但性能很差,我想我会尝试这个模式来改进它。到目前为止,这种体验与我的期望/希望相反。
【问题讨论】:
标签: mongodb mongodb-query aggregation-framework