面试题答案
一键面试聚合管道设计优化
- 减少不必要的阶段:去除聚合管道中对最终结果无实质影响的阶段。例如,如果只需要获取文档的某些特定字段,在
$project
阶段仅选取这些字段,避免获取所有字段,减少数据传输和处理量。db.collection.aggregate([ { $match: { status: "active" } }, { $project: { name: 1, age: 1, _id: 0 } } ]);
- 合理安排阶段顺序:将过滤条件前置,如
$match
阶段应尽量放在管道的前面,先过滤掉大部分不需要的数据,再进行后续的复杂操作。例如:db.collection.aggregate([ { $match: { category: "electronics" } }, { $group: { _id: "$brand", count: { $sum: 1 } } } ]);
- 使用
$facet
优化多个聚合分支:如果需要从同一数据集生成多个不同的报告或分析结果,使用$facet
可以在一次遍历数据中完成多个聚合操作,而不是多次遍历。比如要同时统计不同状态的文档数量和平均评分:db.collection.aggregate([ { $facet: { statusCount: [ { $group: { _id: "$status", count: { $sum: 1 } } } ], averageRating: [ { $group: { _id: null, avgRating: { $avg: "$rating" } } } ] } } ]);
分片集群配置优化
- 分片键选择:确保分片键的选择合理。选择具有高基数(不同值的数量多)且分布均匀的字段作为分片键,避免数据倾斜。例如,对于一个包含用户信息的集合,以用户ID作为分片键通常比以固定的地区字段更好,因为地区字段的值可能有限,容易导致数据集中在某些分片上。
- 调整分片数量:根据数据量和负载情况调整分片数量。如果发现某个分片负载过高,而其他分片负载较低,可以考虑增加分片数量,重新平衡数据分布。但增加分片也会带来额外的管理开销,需要谨慎评估。可以使用
sh.addShard()
命令添加新的分片。 - 副本集配置:优化副本集配置,确保主从节点之间的数据同步效率。合理设置副本集成员的优先级,让性能较好的节点作为主节点,同时配置合适的仲裁节点数量,保证副本集的高可用性。例如,通过修改副本集配置文件,调整成员的
priority
值:cfg = rs.conf(); cfg.members[0].priority = 2; rs.reconfig(cfg);
- 索引优化:在聚合操作涉及的字段上创建合适的索引。例如,如果聚合管道中有
$match
阶段基于某个字段进行过滤,为该字段创建索引可以显著提高查询性能。db.collection.createIndex({ fieldName: 1 });
其他优化
- 启用内存聚合:如果服务器内存充足,可以启用内存聚合。在MongoDB 4.4及更高版本中,通过设置
allowDiskUse
为false
,让聚合操作尽可能在内存中完成,提高性能。但要注意,如果数据量过大,可能会导致操作失败。db.collection.aggregate([ // 聚合管道阶段 ], { allowDiskUse: false });
- 监控与分析:使用MongoDB自带的监控工具,如
mongostat
、mongotop
等,分析性能瓶颈。通过explain()
方法查看聚合操作的执行计划,了解哪些阶段耗时较长,针对性地进行优化。db.collection.aggregate([ // 聚合管道阶段 ]).explain("executionStats");