目前,我正在针对包含用户和事件信息的集合运行聚合。例如:
[
{
$match: {
client: ObjectId('507f1f77bcf86cd799439011'),
location: 'UK'
}
},
{
$group: {
_id: null,
count: {
$sum: 1
}
}
}
]
以上是一个很大的简化,足以说有大约20个不同的变量,如location
,可以进入$match
语句。这两者之间有时还有其他步骤,这就是我使用$group
进行计数的原因。 (而不是count
)
目前我在client
字段上有一个索引,但是没有在其他字段上创建索引(复合或其他)。由于还有很多其他领域,我不能只为所有东西创建索引 - 它太贵了。
问题:当客户端拥有少量文档时,这种方法很有效,但随着数量的增加,聚合必须扫描越来越多的文档。该指数将范围缩小,但这还不够。
创建一个名为p
的附加变量(用于分区),并创建一个复合索引:{ client: 1, p: 1 }
。 p
可以是1
- n
。
不是运行上面的管道,而是运行类似的管道n
次:(对于p
的所有可能值)
[
{
$match: {
client: ObjectId('507f1f77bcf86cd799439011'),
p: 1, // or 2, 3, etc
location: 'UK'
}
},
{
$group: {
_id: null,
count: {
$sum: 1
}
}
}
]
然后可以在应用程序级别合并所有管道的结果。
使用此方法,我可以限制每个查询必须执行的扫描次数,从理论上减少查询时间。
更进一步,此p
值可用作分片键,因此理论上,分析查询可以跨多个分片并行运行。
以前有人做过这样的事吗?我在这个问题上找不到什么。
答案 0 :(得分:1)
对此方法的早期测试表明,它非常有效地运行。并行运行多个count
查询意味着现在计算“总查询时间”:
total time = max(single query time) + combination time
我还没有大规模地测试过这个,但是在中等规模它是一种绝对的享受。
关于此测试的简要统计数据:
client
参数对于少量扫描,这种方法几乎没有任何好处。但是,对于上面的示例,我们将total time
减少到 2-4x 之间。
看起来这种方法在50-100k子集大小之间有一个最佳点。
当然,并行运行大量查询会使您受到其他MongoDB限制。