MST

星途 面试题库

面试题:MongoDB复合键分组在复杂业务场景中的优化应用

考虑一个电商平台的`orders`集合,文档包含`user_id`(用户ID),`product_id`(产品ID),`order_date`(下单日期),`quantity`(购买数量)和`price`(产品单价)。业务需求是分析每个用户在不同月份对不同产品的购买总金额,并且要排除购买总金额小于100的记录,同时按照购买总金额降序排列。假设数据量非常大,需要考虑性能优化。请设计一个高效的MongoDB聚合方案,并解释优化思路。
12.4万 热度难度
数据库MongoDB

知识考点

AI 面试

面试题答案

一键面试
  1. MongoDB聚合方案
db.orders.aggregate([
    // 阶段1:分组计算每个用户在不同月份对不同产品的购买总金额
    {
        $group: {
            _id: {
                user_id: "$user_id",
                month: { $month: "$order_date" },
                product_id: "$product_id"
            },
            total_amount: { $sum: { $multiply: ["$quantity", "$price"] } }
        }
    },
    // 阶段2:排除购买总金额小于100的记录
    {
        $match: {
            total_amount: { $gte: 100 }
        }
    },
    // 阶段3:按照购买总金额降序排列
    {
        $sort: {
            total_amount: -1
        }
    }
]);
  1. 优化思路
    • 分组阶段($group):在$group阶段使用$month操作符提取order_date的月份,将user_idmonthproduct_id作为_id进行分组,这样可以高效地计算每个用户在不同月份对不同产品的购买总金额。在大数据量下,这种分组方式可以充分利用MongoDB的并行处理能力,加快计算速度。
    • 过滤阶段($match):将$match操作放在$group之后,这样可以先在分组计算后再进行过滤,减少需要处理的数据量。如果先进行过滤,可能会导致一些后续需要计算的数据被提前排除,增加不必要的计算。
    • 排序阶段($sort):在数据量很大时,排序操作通常比较消耗资源。将排序操作放在最后,在经过分组和过滤后,数据量已经大幅减少,从而降低排序的压力,提高整体性能。同时,如果数据量极大,可以考虑使用$sortByCount操作替代$sort$sortByCount在某些场景下性能更优。
    • 索引优化:为了进一步提升性能,可以在user_idorder_dateproduct_id字段上创建复合索引。例如:db.orders.createIndex({user_id: 1, order_date: 1, product_id: 1})。这样在聚合操作时,MongoDB可以利用索引快速定位和读取数据,减少磁盘I/O操作,提高查询效率。