Mongodb聚合性能和可伸缩性

时间:2019-10-08 08:04:38

标签: mongodb pipeline aggregation

我正在尝试优化mongodb聚合查询的高可伸缩性,但是我不了解某些内容。

我在 Atlas 服务器M30上的 nodejs 10.x GoogleAppEngine 和mongodb 3.6上运行该软件。

我有很多公寓(10万套,但在不久的将来还会更多),每套公寓都有自己的大小,位置,价格等信息,所有这些信息都存储在单个嵌套文档(数组对象)中数组对象)

因为我必须在这个集合中进行搜索以找到特定的公寓并按计算出的价格对它们进行排序,所以我建立了一个非常大的汇总管道:几乎有 15个步骤,使用了varius $ lookup,$ map,$ reduce超过500行查询

这只是它的流程:


    $aggregation = [
      { $match: { $and: [
        { $geoWithin : '' }, 
        { field1: '' },
        { field2: '' },
        { fieldN: '' }    
      ]}},                   // Initial match 
      {$project: {}},          // pass just a subset of the fields
      {$addFields: {
       $map: {}       // first step of processing data
      }},
      {$addFields: {
       $map: {        // post processing previous data 
         $let: { $map: { $let: {} } }
       }},        
      },
      {$lookup: {}},     // 1th external collection to join
      {$lookup: {}},     // 2th external collection to join
      {$addFields: {}},  // appends 5 more calculated fields
      {$match : { $and:[
        {field1: ''},
        {field2: ''},
        {field3: ''},
      ] }},     // final match on processed data
      {$sort: {}},
      {$group: {}},
      {$project: {}}    // for limiting and paginating results
    ]

一切似乎都正常,查询在 300ms 左右响应,并且用户体验非常好,但是昨天我开始进行一些性能测试,例如并行发送大量请求。工具出问题了!在前10个请求之后,数据库开始进入查询队列,从而使查询的响应时间越来越长,直到单个响应超过 100秒,然后停止响应!

  • 这是正确的方法还是更好地将所有逻辑都添加到nodejs服务器中,并让查询返回所有已过滤但未处理的结果?
  • 还有另一种更好的方法吗?

谢谢

1 个答案:

答案 0 :(得分:1)

似乎我发现问题出在哪里:数据结构本身!

这是整个单元对象的摘录:

{
_id: 
info: {},
pricing: {},
conditioons: {},
...
seasons: [{
  rules:{},
  pricing:{},
   conditions:{},
   ...
   ...,
  }   
  {},
  {},
  {},
  ...
 ]
}

问题是季节阵列!它的大小增加可能会损害mongodb内部的javascript引擎。

解决方案是将所有季节阵列从公寓对象移至单个集合,并带有适当的索引以及一个引用其公寓的字段。在主聚合查询中,将$ lookup阶段与seasons集合一起使用,进行过滤以仅附加需要的季节,即2或3而不是300!。

这个变化对我来说似乎很奇怪,但是它可以将查询执行速度提高10-15倍!

希望有帮助!