【问题标题】:How to improve terrible MongoDB query performance when aggregating with arrays与数组聚合时如何提高糟糕的 MongoDB 查询性能
【发布时间】: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


    【解决方案1】:

    使用索引,它将提高您的查询性能。

    https://docs.mongodb.com/manual/indexes/

    为此,请使用 mongo 指南针检查使用最多的索引,然后一一索引它们以提高其性能。

    在最后获取您需要的字段之后,在聚合中进行投影。

    我希望这可以解决您的问题。但我建议先进行索引。在获取大量数据的情况下,这是一个巨大的优势。

    【讨论】:

      【解决方案2】:

      您需要使用索引来支持您的查询并尽可能简化它。

      您正在查询 updates 字段的第一个元素的 timestamp 字段,因此为此添加一个索引:

      db.updates.createIndex({'updates.0.timestamp': 1})
      

      你只是在寻找一个计数,所以直接得到它:

      db.updates.count({'updates.0.timestamp': {$gte: new Date(...)}})
      

      【讨论】:

      • 嗨!感谢您花时间创建答案。我认为这并不完全适用于我正在尝试做的事情。我的用例按从最旧到最新的顺序将更新插入到数组中,因此.0 将查看最旧的更新而不是最新的更新。我可以修改我的应用程序代码,将更新填充到数组的前面而不是后面,但这似乎违反直觉。此外,我创建了此处指定的索引,但它似乎根本没有帮助我的原始查询的性能(考虑到它的语义,这并不让我感到惊讶)
      • 我刚刚意识到我在示例中添加了0 而不是-1... 非常抱歉。我已经更正了这个例子。
      • 如果您不想更改updates 中元素的顺序,请保留一个单独的字段以包含最新更新的时间戳并在更新时设置它。然后,您可以针对该新字段进行索引和查询。
      猜你喜欢
      • 2019-01-25
      • 1970-01-01
      • 2020-01-10
      • 2011-04-26
      • 2020-05-06
      • 1970-01-01
      • 2017-06-18
      • 2019-01-28
      • 2021-12-15
      相关资源
      最近更新 更多