MongoDB执行计划获取(db.collection.explain())

在RDBMS中,无论那种数据库,都提供了SQL剖析工具,用来解决SQL效率低下的问题。在MongoDB中,也有相应的策略来实现剖析。MongoDB提供了db.collection.explain()方法, cursor.explain()方法,和explain命令去返回查询计划信息和查询计划的执行统计信息。这为我们诊断查询提供了极大的便利,本文主要描述db.collection.explain()的相关用法。

一、db.collection.explain()简介

    支持下列操作返回查询计划
            aggregate(); count(); distinct(); find(); group(); remove(); update() 
    cursor.explain(verbosity)   为一个游标返回其查询执行计划(Reports on the query execution plan for a cursor)
    cursor.explain(verbosity) 最通常的行式为db.collection.find().explain()。其中verbosity说明返回信息的粒度。

    执行计划中几类常见的操作描述
            COLLSCAN 全表扫描        
    IXSCAN 索引扫描          
    FETCH 根据索引去检索文档 
    SHARD_MERGE 合并分片结果 

    db.collection.find().explain(verbose)
            explain()输出一个以文档形式展现的执行计划,可以包括统计信息(可选)。

    参数verbose:
            可选参数。缺省值为queryPlanner,用于查看指定执行计划的特定部分。即给定不同的参数则输出信息的详细程度不同
            常用的包括queryPlanner,executionStats,以及allPlansExecution

    queryPlanner模式
            这个是缺省模式。
            MongoDB运行查询优化器对当前的查询进行评估并选择一个最佳的查询计划

    executionStats模式        
            mongoDB运行查询优化器对当前的查询进行评估并选择一个最佳的查询计划进行执行
            在执行完毕后返回这个最佳执行计划执行完成时的相关统计信息
            对于写操作db.collection.explain()返回关于更新和删除操作的信息,但是并不将修改应用到数据库
            对于那些被拒绝的执行计划,不返回其统计信息

    allPlansExecution模式
            该模式是前2种模式的更细化,即会包括上述2种模式的所有信息
            即按照最佳的执行计划执行以及列出统计信息,而且还会列出一些候选的执行计划
            如果有多个查询计划   ,executionStats信息包括这些执行计划的部分统计信息

    db.collection.explain().find()
            该方法与db.collection.find().explain()类似,但是存在以下关键差异

            The db.collection.explain() method wraps the explain command and is the preferred way to run explain.
            db.collection.explain().find() is similar to db.collection.find().explain() with the following key differences:

            The db.collection.explain().find() construct allows for the additional chaining of query modifiers. 
            For list of query modifiers, see db.collection.explain().find().help().

            The db.collection.explain().find() returns a cursor, which requires a call to .next(), or its alias .finish(), 
            to return the explain() results. If run interactively in the mongo shell, the mongo shell
             automatically calls .finish() to return the results. For scripts, however, you must explicitly call .next(), 
             or .finish(), to return the results. For list of cursor-related methods, see db.collection.explain().find().help().
            db.collection.explain().aggregate() is equivalent to passing the explain option to the db.collection.aggregate() method.

    //获取explain的支持的运算方法
    > db.collection.explain().help()
    Explainable operations
            .aggregate(...) - explain an aggregation operation
            .count(...) - explain a count operation
            .distinct(...) - explain a distinct operation
            .find(...) - get an explainable query
            .findAndModify(...) - explain a findAndModify operation
            .group(...) - explain a group operation
            .remove(...) - explain a remove operation
            .update(...) - explain an update operation
    Explainable collection methods
            .getCollection()
            .getVerbosity()
            .setVerbosity(verbosity)

    //获取explain().find()支持的运算方法 
    > db.collection.explain().find().help()
    Explain query methods
            .finish() - sends explain command to the server and returns the result
            .forEach(func) - apply a function to the explain results
            .hasNext() - whether this explain query still has a result to retrieve
            .next() - alias for .finish()
    Explain query modifiers
            .addOption(n)
            .batchSize(n)
            .comment(comment)
            .count()
            .hint(hintSpec)
            .limit(n)
            .maxTimeMS(n)
            .max(idxDoc)
            .min(idxDoc)
            .readPref(mode, tagSet)
            .showDiskLoc()
            .skip(n)
            .snapshot()
            .sort(sortSpec)
    >       

二、演示相关用法

1、演示db.collection.explain().count()执行计划

//如前面的获取的帮助可知,可以通过db.collection.explain()方式查看相关聚合运算的执行计划,如下:
        > db.version()
        3.2.10
        > db.users.explain().count()
        {
                "queryPlanner" : {
                        "plannerVersion" : 1,
                        "namespace" : "test.users",
                        "indexFilterSet" : false,
                        "winningPlan" : {
                                "stage" : "COUNT"
                        },
                        "rejectedPlans" : [ ]
                },
                "serverInfo" : {
                        "host" : "node233.edq.com",
                        "port" : 27017,
                        "version" : "3.2.10",
                        "gitVersion" : "79d9b3ab5ce20f51c272b4411202710a082d0317"
                },
                "ok" : 1
        }

        //注意,下面将explain()放置到count()之后提示错误 
        > db.users.count().explain()
        2016-12-08T16:53:22.760+0800 E QUERY    [thread1] TypeError: db.users.count(...).explain is not a function :
        @(shell):1:1

2、演示db.collection.explain().update()用法

//先插入一个文档
> db.example.insert({id:1,ename:"leshami",blog:"http://blog.csdn.net/leshami"})
WriteResult({ "nInserted" : 1 })
//下面查看update的执行计划
> db.example.explain().update({id:1},{$set:{name:"robinson_0612"}})
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test.example",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "id" : {
                                "$eq" : 1
                        }
                },
                "winningPlan" : {
                        "stage" : "UPDATE",
                        "inputStage" : {
                                "stage" : "COLLSCAN",
                                "filter" : {
                                        "id" : {
                                                "$eq" : 1
                                        }
                                },
                                "direction" : "forward"
                        }
                },
                "rejectedPlans" : [ ]
        },
        "serverInfo" : {
                "host" : "node233.edq.com",
                "port" : 27017,
                "version" : "3.2.10",
                "gitVersion" : "79d9b3ab5ce20f51c272b4411202710a082d0317"
        },
        "ok" : 1
}

//再次查看文档,如下,文档并没有被更新,正如前文所述,该方式并不将修改应用到数据库
> db.example.find().pretty()
{
        "_id" : ObjectId("584924b4de4a7c9eeef9ef9d"),
        "id" : 1,
        "ename" : "leshami",
        "blog" : "http://blog.csdn.net/leshami"
}

//同样将update前置到explain之前也是错误的
> db.example.update({id:1},{$set:{name:"robinson_0612"}}).explain()
2016-12-08T17:24:24.708+0800 E QUERY    [thread1] TypeError: db.example.update(...).explain is not a function :
@(shell):1:1

3、执行计划相关描述

//演示演示集合文档数据,可以参考:http://blog.csdn.net/leshami/article/details/52672310
//从下面的查询结果可知,缺省情况下,explain包括2个部分,一个是queryPlanner,一个是serverInfo
//如果使用了executionStats或者allPlansExecution,则还会返回executionStats信息
> db.persons.find({age:26}).explain()
{
        "queryPlanner" : {
                "plannerVersion" : 1,              //查询计划版本
                "namespace" : "test.persons",      //被查询对象
                "indexFilterSet" : false,          //是否使用到了索引来过滤
                "parsedQuery" : {                  //解析查询,即过滤条件是什么
                        "age" : {                  //此处为age=26
                                "$eq" : 26
                        }
                },
                "winningPlan" : {                  //最佳的执行计划
                        "stage" : "COLLSCAN",      //COLLSCAN为集合扫描
                        "filter" : {               //过滤条件
                                "age" : {
                                        "$eq" : 26
                                }
                        },
                        "direction" : "forward"    //方向:forward
                },
                "rejectedPlans" : [ ]              //拒绝的执行计划,此处没有
        },
        "serverInfo" : {                           //服务器信息,包括主机名,端口,版本等。
                "host" : "node233.edq.com",
                "port" : 27017,
                "version" : "3.2.10",
                "gitVersion" : "79d9b3ab5ce20f51c272b4411202710a082d0317"
        },
        "ok" : 1
}

4、执行计划统计信息描述

//下面查看executionStats,使用一个大的集合,以便观察执行统计信息
> db.inventory.find({id:500}).explain("executionStats")
{
        "queryPlanner" : {
             .........
        },
        "executionStats" : {                   //执行计划相关统计信息
                "executionSuccess" : true,     //执行成功的状态
                "nReturned" : 1,               //返回结果集数目
                "executionTimeMillis" : 21896, //执行所需的时间,毫秒
                "totalKeysExamined" : 0,       //索引检查的时间
                "totalDocsExamined" : 5000000, //检查文档总数
                "executionStages" : {          
                        "stage" : "COLLSCAN",  //使用集合扫描方式
                        "filter" : {           //过滤条件
                                "id" : {
                                        "$eq" : 500
                                }
                        },
                        "nReturned" : 1,       //返回结果集数目  
                        "executionTimeMillisEstimate" : 19230, //预估的执行时间,毫秒
                        "works" : 5000002,   //工作单元数,一个查询会被派生为一些小的工作单元
                        "advanced" : 1,      //优先返回的结果数目
                        "needTime" : 5000000,
                        "needYield" : 0,
                        "saveState" : 39065,
                        "restoreState" : 39065,
                        "isEOF" : 1,
                        "invalidates" : 0,
                        "direction" : "forward",   //方向
                        "docsExamined" : 5000000   //文档检查数目
                }
        },
        "serverInfo" : {
         ...........
        "ok" : 1
}

//其他更详细的描述可以参考
https://docs.mongodb.com/manual/reference/explain-results/#executionstats

5、获取所有的执行计划

//如下所示,由于当前我们没有多个执行计划,因此仅返回一个执行计划
> db.persons.find({age:26}).explain("allPlansExecution")
{
        "queryPlanner" : {
                "plannerVersion" : 1,
                "namespace" : "test.persons",
                "indexFilterSet" : false,
                "parsedQuery" : {
                        "age" : {
                                "$eq" : 26
                        }
                },
                "winningPlan" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "age" : {
                                        "$eq" : 26
                                }
                        },
                        "direction" : "forward"
                },
                "rejectedPlans" : [ ]
        },
        "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 3,
                "executionTimeMillis" : 0,
                "totalKeysExamined" : 0,
                "totalDocsExamined" : 11,
                "executionStages" : {
                        "stage" : "COLLSCAN",
                        "filter" : {
                                "age" : {
                                        "$eq" : 26
                                }
                        },
                        "nReturned" : 3,
                        "executionTimeMillisEstimate" : 0,
                        "works" : 13,
                        "advanced" : 3,
                        "needTime" : 9,
                        "needYield" : 0,
                        "saveState" : 0,
                        "restoreState" : 0,
                        "isEOF" : 1,
                        "invalidates" : 0,
                        "direction" : "forward",
                        "docsExamined" : 11
                },
                "allPlansExecution" : [ ]
        },
        "serverInfo" : {
                "host" : "node233.edq.com",
                "port" : 27017,
                "version" : "3.2.10",
                "gitVersion" : "79d9b3ab5ce20f51c272b4411202710a082d0317"
        },
        "ok" : 1
}                   

DBA牛鹏社(SQL/NOSQL/LINUX)

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值