目前我正在对包含用户和事件信息的集合运行聚合。例如:
[
{
$match: {
client: ObjectId('507f1f77bcf86cd799439011'),
location: 'UK'
}
},
{
$group: {
_id: null,
count: {
$sum: 1
}
}
}
]
Run Code Online (Sandbox Code Playgroud)
以上是一个很大的简化,足以说明大约有 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
}
}
}
]
Run Code Online (Sandbox Code Playgroud)
然后可以在应用程序级别合并所有管道的结果。
使用这种方法,我可以限制每个查询必须执行的扫描次数,理论上减少了查询时间。
更进一步,该p值可以用作分片键,因此理论上,分析查询可以跨多个分片并行运行。
有没有人做过这样的事情?我在这个主题上发现的很少。
对这种方法的早期测试表明它确实非常有效。count并行运行多个查询意味着“总查询时间”计算现在为:
total time = max(single query time) + combination time
Run Code Online (Sandbox Code Playgroud)
我还没有在大规模上测试过这个,但在中等规模上它绝对是一种享受。
有关此测试的简要统计数据:
client我关心的参数对于少量扫描,这种方法几乎没有任何好处。然而,对于上面的示例,我们得到了2-4xtotal time之间的减少。
看起来这种方法在 50-100k 子集大小之间有一个最佳点。
当然,并行运行大量查询可能会让您受到其他 MongoDB 限制的影响。
| 归档时间: |
|
| 查看次数: |
2536 次 |
| 最近记录: |