如何优化 mongodb 聚合查询

How to optimize the mongodb aggregate query

我有一个集合,其中包含大约 10.2M records.My 聚合查询需要大约 6 秒才能发回 record.How 我是否优化我的聚合查询。?索引在 token0address、token1address 和 timestamp 字段上定义。

下面是我的查询

  {
    $match: {
      $or: [
        {
          token0Address: quoteCurrency,
        },
        {
          token1Address: quoteCurrency,
        },
      ],
      timestamp: {
        $gte: Number(historyDTO.from),
        $lte: Number(historyDTO.to),
      },
    },
  },
  {
    $group: {
      _id: idObj,
      transactionDate: { $first: '$transactionDate' },
      timestamp: { $first: '$timestamp' },
      minimum_price: { $min: '$priceInToken0' },
      maximum_price: { $max: '$priceInToken0' },
      median_price: { $avg: '$priceInToken0' },
      open_price: { $first: '$priceInToken0' },
      close_price: { $last: '$priceInToken0' },
      volume: { $sum: '$priceInToken0' },
    },
  },
  { $sort: { timestamp: -1 } },
  { $skip: 0 },
  { $limit: Number(historyDTO.countback) },

idObj 看起来 this.It 也包含其他组合

if (last === 'H') {
idObj = {
  day: { $dayOfYear: '$transactionDate' },
  hour: {
    $subtract: [
      { $hour: '$transactionDate' },
      { $mod: [{ $hour: '$transactionDate' }, parseInt(exceptLast)] },
    ],
  },
};

}

我会提到一些我认为可以提高性能的变化,但总的来说,我会说这是非常优化的,我个人不会花更多的时间来优化它,除非它是许多进程的组成部分并且每毫秒运行时间很重要。

  1. token0Addresstoken1Address两个字段创建复合索引,现在Mongo正在使用这些索引,但是它需要根据在 timestamp 上。如果您可以将两个索引构建为复合 {token0Address: 1, timestamp: 1},那么 Mongo 可以更快地完成 $match 阶段。 (显然取决于给定范围和匹配文档的比例)。

  2. 尽可能改变idObj,你提到idObj有不同的结构,也许其中一些有冗余可以消除,这里我们真的不能做任何事情由于 $mod 运算符的动态使用,另一种可能性是预处理所需的字段(例如在这种情况下保存 $hour 结果,因此我们停止使用此操作)。

  3. 最后一个选项更像是一个技巧,但如果您了解数据分布和查询的启发式方法,您可能能够添加更早的限制并处理更少的数据。这通常不是一个现实的选择,尤其是在数据规模较小的情况下。