注册

详解MongoDB的explain()函数:返回执行计划和性能指标

MongoDB是一款基于文档的数据库,为了优化查询性能,提供了explain()函数用于分析查询语句的执行情况。本文将详细介绍explain()函数的作用和使用方法,并且提供两个实例进行说明。

1. 作用

explain()函数的作用是分析查询语句的执行计划,输出查询过程中的详细信息,包括使用到的索引、扫描文档数、查询时间等,根据输出结果可以优化查询语句、修改索引等,以达到更好的查询性能。

2. 使用方法

explain()函数可以直接在查询语句中使用,格式如下:

db.collection.find(query).explain([verbosity])

其中,query表示查询条件,verbosity表示输出详细程度,有三种:queryPlannerexecutionStatsallPlansExecution,默认是queryPlanner

实例1:

假设我们有一张students表,包含了每个学生的姓名、年龄、成绩等信息,现在我们需要查询年龄大于20岁的学生列表,并且按照成绩从高到低排序。我们可以使用如下查询语句:

db.students.find({age: {$gt: 20}}).sort({score: -1}).limit(10)

输出结果如下:

{ "_id" : ObjectId("6161d87b9ed21bc1fee93c4e"), "name" : "小明", "age" : 25, "score" : 89 }
{ "_id" : ObjectId("6161d87b9ed21bc1fee93c4f"), "name" : "小红", "age" : 23, "score" : 88 }
...

我们也可以使用explain()函数来分析该查询语句的执行计划:

db.students.find({age: {$gt: 20}}).sort({score: -1}).limit(10).explain("executionStats")

输出结果如下:

{
    "executionStats" : {
        "executionSuccess": true,
        "nReturned": 10,
        "executionTimeMillis": 0,
        "totalKeysExamined": 10,
        "totalDocsExamined": 10,
        //......
    },
    //......
}

可以看出这条查询语句使用了executionStats输出详细程度,执行过程中考虑了索引,扫描了10条文档,查询时间为0毫秒。

实例2:

假设我们有一张orders表,包含了每个订单的时间、用户ID、订单状态等信息,我们想获取一个用户在过去7天内提交的所有订单,以及每个订单的详细信息。我们可以使用如下查询语句:

db.orders.aggregate([
{
   $match: {
      userid: "12234567",
      orderdate: {$gte: new Date(new Date().getTime() - (7 * 24 * 60 * 60 * 1000))}
   }
},
{
   $lookup: {
      from: "orderdetails",
      localField : "orderid",
      foreignField : "orderid",
      as : "orderdetails"
   }
}
])

输出结果如下:

{ "_id" : ObjectId("6162279a9ed21bc1fee93c50"), "userid" : "12234567", "orderdate" : "2021-10-08", "orderid" : "10000002", "orderdetails" : [ { "_id" : ObjectId("616237629ed21bc1fee93c51"), "orderid" : "10000002", "productname" : "iPhone 13", "quantity" : 1, "price" : 7999 } ] }
{ "_id" : ObjectId("616227b69ed21bc1fee93c54"), "userid" : "12234567", "orderdate" : "2021-10-08", "orderid" : "10000005", "orderdetails" : [ { "_id" : ObjectId("616238ad9ed21bc1fee93c55"), "orderid" : "10000005", "productname" : "MacBook Pro", "quantity" : 1, "price" : 15999 } ] }
...

我们也可以使用explain()函数来分析该查询语句的执行计划:

db.orders.aggregate([
{
   $match: {
      userid: "12234567",
      orderdate: {$gte: new Date(new Date().getTime() - (7 * 24 * 60 * 60 * 1000))}
   }
},
{
   $lookup: {
      from: "orderdetails",
      localField : "orderid",
      foreignField : "orderid",
      as : "orderdetails"
   }
}
]).explain("executionStats")

输出结果如下:

{
    "stages" : [
        {
            "$cursor" : {
                "query" : {
                    "userid" : "12234567",
                    "orderdate" : { "$gte" : ISODate("2021-10-04T11:09:00.818Z") }
                },
                "queryPlanner" : {
                    "plannerVersion" : 1,
                    "namespace" : "test.orders",
                    "indexFilterSet" : false,
                    "parsedQuery" : {...},
                    "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {...}
                            "indexName" : "...",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {...},
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : {...},
                            "indexBounds" : {...}
                        }
                    },
                    "rejectedPlans" : [...]
                }
            }
        },
        {
            "$lookup" : {
                "from" : "orderdetails",
                "localField" : "orderid",
                "foreignField" : "orderid",
                "as" : "orderdetails"
            }
        }
    ],
    "serverInfo" : {...},
    "ok" : 1,
    //......
}

可以看出这条聚合语句使用了executionStats输出详细程度,其中包括了查询优化器的工作过程,查询计划的选择、拒绝等信息。

3. 结论

通过explain()函数能够更好的分析查询语句的执行计划,便于进行查询优化,通常在开发的过程中需要及时分析查询语句的执行计划,以达到更好的性能优化。