专栏首页乐沙弥的世界MongoDB执行计划获取(db.collection.explain())

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
}                   

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Oracle 12c多租户架构及优缺点

    Oracle的多租户和MySQL,MSSQL的类似,把之前的一个实例对一个数据库的情形(RAC是多个实例对一个数据库)整合成了一个实例下可以挂多个数据库,并且定...

    Leshami
  • Windows平台下安装MongoDB

    wmic os get caption wmic os get osarchitecture

    Leshami
  • SQL server 2005 切换分区表

    如转载,请注明出处:http://blog.csdn.net/robinson_0612/archive/2009/11/10/4794371.aspx

    Leshami
  • 敞开的地狱之门:Kerberos协议的滥用

    作者 Rabbit_Run 微软的活动目录默认使用Kerberos处理认证请求。在BlackHat 2014上神器Mimikatz的作者剖析了微软实现的Kerb...

    FB客服
  • Leetcode【523、525、560、974】

    这道题是给一个非负整数数组和整数 k,判断数组是否含有连续子数组,其大小至少为 2,总和为 k 的倍数,即总和为 n*k,其中 n 也是一个整数。

    echobingo
  • python爬取连续一字板股票及当时日期数据【原创分享】

    逆向小白
  • python爬取链家租房之获取房屋页面的详细信息(房名,地址,房价,面积,url)

    __author__ = 'Lee' from bs4 import BeautifulSoup import requests import time url...

    98k
  • 惊艳!Python3 的这几个特性

    距离官方放弃Python2的时间越来越近,很多项目也逐渐的开始放弃对Python2的支持,比如Django,IPython这些框架就走在了最前列,Python2...

    py3study
  • 云计算的可迁移性为什么很难完美实现

    导语 可迁移性意味着企业可以将应用程序从一个主机环境迁移到另一个,其包括云平台之间的迁移。容器是一种将应用程序和操作系统封装到可以在支持Docker或Kuber...

    静一
  • Linux 下的 Modprobe 命令

    本文最先发布在: https://www.itcoder.tech/posts/modprobe-command-in-linux/

    雪梦科技

扫码关注云+社区

领取腾讯云代金券