为什么相同的mongo查询通过聚合比通过find需要更长的时间?

时间:2018-03-06 04:22:03

标签: mongodb mongodb-query aggregation-framework

所以,我有1000万人的文件。这个查询:

db.getCollection('people').find({'address.zip': '87447'}).sort({'name.last': -1}).limit(3)

返回< 20ms的

此查询:

db.getCollection('people').aggregate([{$match: {'address.zip': '87447'}},{$sort: {'name.last': -1}}, {$limit: 3}])

返回> 20S

我在address.zipname.last

上有索引

只有大约100个符合$match标准的文档...

...折流

这里有解释:

找到

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "people.people",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "address.zip" : {
                "$eq" : "87447"
            }
        },
        "winningPlan" : {
            "stage" : "SORT",
            "sortPattern" : {
                "name.last" : -1.0
            },
            "limitAmount" : 3,
            "inputStage" : {
                "stage" : "SORT_KEY_GENERATOR",
                "inputStage" : {
                    "stage" : "FETCH",
                    "inputStage" : {
                        "stage" : "IXSCAN",
                        "keyPattern" : {
                            "address.zip" : 1
                        },
                        "indexName" : "address.zip_1",
                        "isMultiKey" : false,
                        "multiKeyPaths" : {
                            "address.zip" : []
                        },
                        "isUnique" : false,
                        "isSparse" : false,
                        "isPartial" : false,
                        "indexVersion" : 2,
                        "direction" : "forward",
                        "indexBounds" : {
                            "address.zip" : [
                                "[\"87447\", \"87447\"]"
                            ]
                        }
                    }
                }
            }
        },
        "rejectedPlans" : [
            {
                "stage" : "LIMIT",
                "limitAmount" : 3,
                "inputStage" : {
                    "stage" : "FETCH",
                    "filter" : {
                        "address.zip" : {
                            "$eq" : "87447"
                        }
                    },
                    "inputStage" : {
                        "stage" : "IXSCAN",
                        "keyPattern" : {
                            "name.last" : 1
                        },
                        "indexName" : "name.last_1",
                        "isMultiKey" : false,
                        "multiKeyPaths" : {
                            "name.last" : []
                        },
                        "isUnique" : false,
                        "isSparse" : false,
                        "isPartial" : false,
                        "indexVersion" : 2,
                        "direction" : "backward",
                        "indexBounds" : {
                            "name.last" : [
                                "[MaxKey, MinKey]"
                            ]
                        }
                    }
                }
            }
        ]
    },
    "serverInfo" : {
        "host" : "00caaca2f8e7",
        "port" : 27017,
        "version" : "3.7.2",
        "gitVersion" : "ca0a855dfc0f479d85b76a640b12a259c0547310"
    },
    "ok" : 1.0
}

聚合

{
    "stages" : [
        {
            "$cursor" : {
                "query" : {
                    "address.zip" : "87447"
                },
                "sort" : {
                    "name.last" : -1
                },
                "limit" : NumberLong(3),
                "queryPlanner" : {
                    "plannerVersion" : 1,
                    "namespace" : "people.people",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                        "address.zip" : {
                            "$eq" : "87447"
                        }
                    },
                    "winningPlan" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "address.zip" : {
                                "$eq" : "87447"
                            }
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "name.last" : 1
                            },
                            "indexName" : "name.last_1",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "name.last" : []
                            },
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "backward",
                            "indexBounds" : {
                                "name.last" : [
                                    "[MaxKey, MinKey]"
                                ]
                            }
                        }
                    },
                    "rejectedPlans" : []
                }
            }
        }
    ],
    "ok" : 1.0
}

有关问题所在位置或如何解决问题的任何建议?

2 个答案:

答案 0 :(得分:1)

聚合并查找使用不同的查询计划,因为当前聚合显式请求使用非阻塞计划(即可以使用索引提供排序顺序的计划)。

有一个Jira票证(https://jira.mongodb.org/browse/SERVER-7568)跟踪工作以改进这一点,因为如果少量文档与查询匹配,在内存中排序的查询计划会更快。

但是,在所有情况下,具有满足filter和sort子句的复合索引对于find和aggregate都会表现最佳。在您的情况下,这将是{"address.zip":1, "name.last":1}

的索引

请注意,从3.6开始,您还可以provide hint to aggregate指定要使用的索引。

答案 1 :(得分:-1)

find()方法用于在单个集合中查找数据作为您的条件。而当您需要使用一个或多个表执行aggregation时使用joins()。我并不是说您无法使用aggregation,但如果您可以使用find()获取数据,则无需使用aggregation。如果您使用join()在其他集合中拥有一些唯一键,也可以执行populate

  profileModel.find({
      _id: ObjectId("5a65dbba59d1d9128dd353b3")
  })
  .populate('pickupLocId').then((data) => {
      res.send(data);
  })