mongodb - 提高 MongoDB 上聚合查询的性能
问题描述
我对 mongodb 的聚合框架有一个大问题。我会尽力解释这种情况,但代码很清楚。
我们有一个集合 category 和 notes,每个 note 都有一个 category id 字段和 createdAt 字段,我们希望得到每个类别的最后一个 note。
因此,我们创建了下一个 agreggate 函数:
(async () =>{
//busco las categorias
const categoryCollection = db.collection('category');
const categoryList = await categoryCollection.find({},{ projection:{name: 1} }).toArray();
//genero un arrays de ids de categoria
const categoryIds = categoryList.map(function(e) {
return e._id;
});
//busco una nota por categoria ordenadas por fecha de creacion de forma descendente
const articlesColl = db.collection('note');
const articles = await articlesColl.aggregate([
{ $match: { "category":{$in: categoryIds }}},
{ $sort: { createdAt: -1 }},
{
$group: {
_id: "$category",
note: { $first: "$$ROOT"}
}
},
{ $replaceRoot: { newRoot: "$note" } },
{ $project : { _id : 1 ,title : 1, image : 1, category:1} },
{ $skip: skip},
{ $limit : limit }
],{allowDiskUse: true}).toArray();
callback(null, success(
//reemplazo los category id con el nombre
articles.map(
function(doc){
doc.categoryName = categoryList.find( e => e._id.equals(doc.category)).name;
return doc;
}
)
));
此查询按每个类别获取最后一个音符,但此“糟糕”的表现。
我使用 mongo atlas,警报向我显示:
查询低效率分数:258393,执行计数 4,平均执行时间 2872 毫秒
这是查询的一个例子。
0: Object $match: Object category: Object $in: Array[23] 0: 5a4536cd920f3a5acdf33a60 1: 5a4536cd920f3a5acdf33a55 2: 5a4536cd920f3a5acdf33a53 3: 5a4536cd920f3a5acdf33a66 4: 5a4536cd920f3a5acdf33a5a 5: 5a4536cd920f3a5acdf33a56 6: 5a4536cd920f3a5acdf33a51 7: 5a4536cd920f3a5acdf33a58 8: 5a4536cd920f3a5acdf33a5b 9: 5a4536cd920f3a5acdf33a57 10: 5a4536cd920f3a5acdf33a63 11: 5a4536cd920f3a5acdf33a5d 12: 5a4536cd920f3a5acdf33a5c 13: 5a4536cd920f3a5acdf33a59 14: 5a4536cd920f3a5acdf33a52 15: 5a4536cd920f3a5acdf33a5e 16: 5a4536cd920f3a5acdf33a65 17: 5a4536cd920f3a5acdf33a61 18: 5b202ef5d03337b3a0227daf 19: 5a4536cd920f3a5acdf33a64 20: 5a4536cd920f3a5acdf33a62 21: 5a4536cd920f3a5acdf33a5f 22: 5a4536cd920f3a5acdf33a54 1: Object $sort: Object createdAt: -1 2: Object $group:对象_id:$category 注意:对象$first:$$ROOT 3:对象$replaceRoot:对象newRoot:$note 4:对象 $project:对象 _id:1 标题:1 图像:1 类别:1 5:对象 $skip:0 6:对象 $limit:8 Fri Aug 17 2018 10:11am 6283 ms 1033573 / 8nScanned / nReturned
这里最大的问题是这个查询真的很慢,有时需要超过 6 秒才能完成。
一些想法来改善这一点?
解决方案
该查询低效率分数意味着对于您返回的每个文档,查询都会检查 258393 个文档。
您是否考虑过迭代 categoryList 并使用 find 来获取最新的注释?
const articles = categoryList.map(function(e) {
return await articlesColl.Find(x => x.category == e._id).Sort({ createdAt: -1 }).Limit(1)
});
如果您在 {category:1, createdAt:-1} 上创建了一个索引,则运行它只需要检查每个类别的单个文档(在您的示例中总共 23 个)。即使有额外的网络往返,将检查的文档数量减少 100,000 倍应该可以让它们在明显少于 6 秒的时间内完成。
推荐阅读
- java - Java Linked List 无法将项目添加到末尾
- android - findLastCompletelyVisibleItemPosition 返回 -1
- python - 当 .get 返回 None 时简化 if 条件
- sql - 尝试使用子查询在两个不同的列中产生 2013 年的销售额和 2012 年的销售额
- json - 为什么@RequestBody 得到一个具有空属性的对象
- graphql - 通过身份池联合的开发人员身份验证身份无法在 Amplify 项目中进行 AppSync 调用
- java - Cucumber DataTable .raw() 不再有效(io.cucumber:4.7.2)?
- forms - CakePHP 表单提交疑难解答
- apache-spark - 为什么 `spark.range(100).orderBy('id', ascending=False).rdd` 不懒惰并触发动作?
- html - Chrome 自动填充上的预填充值在选择前大小不同