MongoDB中的慢查询使用group进行集合范围的聚合查询

Abh*_*rma 5 aggregate mongoose mongodb node.js

我在使用NodeJS + Express + MongoDB开发的API上存在性能问题.

在使用特定产品的$ match运行聚合时,性能很好,但对于开放式搜索,它确实很慢.

我想在两个列上运行一个组:country和exporter,然后在country上将结果限制为每组3个结果.

要求:每个国家的独特出口商总数以及每个国家的任何3个记录.

explain()我的运行上我aggregate function得到以下关键指针,标志着我的查询很慢.如果我错了,请纠正我.

  1. "indexFilterSet": false
  2. "winningPlan": { "stage": "COLLSCAN", "direction": "forward" },

查询9,264,947记录和时间是关于32 seconds.我已经尝试过使用复合索引以及单字段索引,但它根本没有帮助,因为我觉得索引没有被用作$match{}

下面是我使用的MongoDB上运行查询猫鼬司机

Model.aggregate([
  {"$match" : query},
  { $group : {_id: {country: "$Country", exporter: "$Exporter"}, id: {$first: "$_id"}, product: { $first: "$Description" }}},
  { $group : {_id: "$_id.country", data: {$push: { id: "$id", company: "$_id.exporter", product: "$product" }}, count:{$sum:1}}},
  { "$sort": { "count": -1 } },
  { 
    $project: { 
      "data": { "$slice": [ "$data", 3 ] },
      "_id": 1,
      "count": 1
    }
  },
]).allowDiskUse(true).explain()
Run Code Online (Sandbox Code Playgroud)

其中,查询是动态构建的,默认情况下为空,{}用于集合范围的搜索.索引字段是

  1. 复合指数: {Country: 1, Exporter: 1}

  2. 文字索引: {Description: "text"}

完整解释()回复:

{
"success": "Successfull",
"status": 200,
"data": {
    "stages": [
        {
            "$cursor": {
                "query": {},
                "fields": {
                    "Country": 1,
                    "Description": 1,
                    "Exporter": 1,
                    "_id": 1
                },
                "queryPlanner": {
                    "plannerVersion": 1,
                    "namespace": "db.OpenExportData",
                    "indexFilterSet": false,
                    "parsedQuery": {},
                    "winningPlan": {
                        "stage": "COLLSCAN",
                        "direction": "forward"
                    },
                    "rejectedPlans": []
                }
            }
        },
        {
            "$group": {
                "_id": {
                    "country": "$Country",
                    "exporter": "$Exporter"
                },
                "id": {
                    "$first": "$_id"
                },
                "product": {
                    "$first": "$Description"
                }
            }
        },
        {
            "$group": {
                "_id": "$_id.country",
                "data": {
                    "$push": {
                        "id": "$id",
                        "company": "$_id.exporter",
                        "product": "$product"
                    }
                },
                "count": {
                    "$sum": {
                        "$const": 1
                    }
                }
            }
        },
        {
            "$sort": {
                "sortKey": {
                    "count": -1
                }
            }
        },
        {
            "$project": {
                "_id": true,
                "count": true,
                "data": {
                    "$slice": [
                        "$data",
                        {
                            "$const": 3
                        }
                    ]
                }
            }
        }
    ],
    "ok": 1
}
}
Run Code Online (Sandbox Code Playgroud)

集合大小:9,264,947记录和10.2 GB

响应时间:32154毫秒

随着我的集合的大小增加,查询变得越来越慢.

sim*_*gix 0

如果您的查询{},mongo 引擎会跳过该$match阶段并直接进入$group. 将不使用任何索引。您可以从explain()结果中验证上面的内容。和管道运算符在出现在管道开头时$match可以$sort利用索引。查看您的管道,您使用CountryExporter对它们进行分组。您可以做的是在 上创建索引{Country: 1, Exporter: 1},并将其用作$sort管道{Country: 1, Exporter: 1}的第一阶段。这将使$group效率更高。