如何优化 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)] },
],
},
};
}
我会提到一些我认为可以提高性能的变化,但总的来说,我会说这是非常优化的,我个人不会花更多的时间来优化它,除非它是许多进程的组成部分并且每毫秒运行时间很重要。
为token0Address
和token1Address
两个字段创建复合索引,现在Mongo正在使用这些索引,但是它需要根据在 timestamp
上。如果您可以将两个索引构建为复合 {token0Address: 1, timestamp: 1}
,那么 Mongo 可以更快地完成 $match
阶段。 (显然取决于给定范围和匹配文档的比例)。
尽可能改变idObj
,你提到idObj
有不同的结构,也许其中一些有冗余可以消除,这里我们真的不能做任何事情由于 $mod
运算符的动态使用,另一种可能性是预处理所需的字段(例如在这种情况下保存 $hour
结果,因此我们停止使用此操作)。
最后一个选项更像是一个技巧,但如果您了解数据分布和查询的启发式方法,您可能能够添加更早的限制并处理更少的数据。这通常不是一个现实的选择,尤其是在数据规模较小的情况下。
我有一个集合,其中包含大约 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)] },
],
},
};
}
我会提到一些我认为可以提高性能的变化,但总的来说,我会说这是非常优化的,我个人不会花更多的时间来优化它,除非它是许多进程的组成部分并且每毫秒运行时间很重要。
为
token0Address
和token1Address
两个字段创建复合索引,现在Mongo正在使用这些索引,但是它需要根据在timestamp
上。如果您可以将两个索引构建为复合{token0Address: 1, timestamp: 1}
,那么 Mongo 可以更快地完成$match
阶段。 (显然取决于给定范围和匹配文档的比例)。尽可能改变
idObj
,你提到idObj
有不同的结构,也许其中一些有冗余可以消除,这里我们真的不能做任何事情由于$mod
运算符的动态使用,另一种可能性是预处理所需的字段(例如在这种情况下保存$hour
结果,因此我们停止使用此操作)。最后一个选项更像是一个技巧,但如果您了解数据分布和查询的启发式方法,您可能能够添加更早的限制并处理更少的数据。这通常不是一个现实的选择,尤其是在数据规模较小的情况下。