MST
星途 面试题库

面试题:MongoDB $avg累加器函数在海量电商数据分析及性能优化中的应用

在一个大型电商数据库的MongoDB集合orders里,文档数量达数十亿,结构为{order_id: 订单ID, user_id: 用户ID, order_amount: 订单金额, order_time: 订单时间, product_list: [产品列表]}。现需要分析每个用户每月的平均订单金额,同时考虑到数据量巨大,如何优化使用$avg累加器函数的聚合查询性能,给出详细的聚合管道和优化策略。
27.7万 热度难度
数据库MongoDB

知识考点

AI 面试

面试题答案

一键面试

聚合管道

[
    // 步骤1:匹配有效的文档(可根据实际情况添加过滤条件)
    {
        $match: {
            order_amount: { $exists: true, $gt: 0 }
        }
    },
    // 步骤2:提取年份和月份信息
    {
        $addFields: {
            year: { $year: "$order_time" },
            month: { $month: "$order_time" }
        }
    },
    // 步骤3:按用户ID、年份和月份进行分组
    {
        $group: {
            _id: {
                user_id: "$user_id",
                year: "$year",
                month: "$month"
            },
            total_amount: { $sum: "$order_amount" },
            order_count: { $sum: 1 }
        }
    },
    // 步骤4:计算平均订单金额
    {
        $addFields: {
            average_amount: {
                $cond: {
                    if: { $gt: ["$order_count", 0] },
                    then: { $divide: ["$total_amount", "$order_count"] },
                    else: 0
                }
            }
        }
    },
    // 步骤5:格式化输出结果
    {
        $project: {
            _id: 0,
            user_id: "$_id.user_id",
            year: "$_id.year",
            month: "$_id.month",
            average_amount: 1
        }
    }
]

优化策略

  1. 索引优化
    • order_amountorder_timeuser_id字段上创建复合索引。例如:db.orders.createIndex({user_id: 1, order_time: 1, order_amount: 1})。这可以加速$match阶段的过滤操作,因为$match可以利用索引快速定位符合条件的文档。
    • 索引的顺序很重要,user_id放在第一位是因为分组是基于user_idorder_time其次用于按时间范围筛选,order_amount用于金额相关的过滤。
  2. 分阶段聚合
    • 如果数据量特别巨大,可以考虑分阶段聚合。首先在部分数据子集上运行聚合操作,得到每个子集的部分结果。然后对这些部分结果再次进行聚合,得到最终结果。这可以减少单个聚合操作处理的数据量,提高性能。
    • 例如,可以按照日期范围(如每周或每月)对数据进行划分,分别在每个日期范围内执行上述聚合管道,然后将这些中间结果再次聚合得到最终的每个用户每月平均订单金额。
  3. 使用内存限制
    • 在执行聚合操作时,可以设置allowDiskUse选项为true,允许MongoDB在内存不足时使用磁盘。但要注意,磁盘使用会比内存使用慢,所以要根据服务器的内存情况和数据量合理设置。例如:db.orders.aggregate(aggregationPipeline, {allowDiskUse: true})
  4. 数据预处理
    • 可以在数据插入时进行一些预处理,比如提前计算一些聚合需要的中间值并存储在文档中。例如,可以在插入订单时,计算并存储该用户到当前订单为止的累计订单金额和订单数量,这样在聚合时可以减少计算量。
  5. 并行处理
    • 如果服务器是多核CPU,可以利用MongoDB的并行处理能力。在执行聚合操作时,MongoDB会自动根据服务器的CPU核心数并行处理数据,提高聚合效率。确保服务器的硬件资源能够充分利用,避免出现CPU瓶颈。