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

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 在RDBMS中,无论那种数据库,都提供了SQL剖析工具,用来解决SQL效率低下的问题。在MongoDB中,也有相应的策略来实现剖析。

在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)

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
SQL NoSQL MySQL
MongoDB 执行计划 & 优化器简介 (上)
最近,由于工作需求去了解一下Query是如何在MongoDB内部进行处理,从而丢给存储引擎的。里面涉及了Query执行计划和优化器的相关代码,MongoDB整体思路设计的干净利落,有些地方深入挖一下其实还是能有些优化点的。本文会涉及一条Query被parse之后一路走到引擎之前,都做了那些事情,分析基于MongoDB v3.4.6代码。由于篇幅过长,文章分为上下两篇,分别介绍执行计划 & 优化器和
3770 0
|
2月前
|
存储 关系型数据库 MySQL
一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB区别,适用场景
一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB——特点、性能、扩展性、安全性、适用场景比较
|
3月前
|
存储 NoSQL 关系型数据库
非关系型数据库-MongoDB技术(二)
非关系型数据库-MongoDB技术(二)
|
3月前
|
NoSQL 关系型数据库 MongoDB
非关系型数据库-MongoDB技术(一)
非关系型数据库-MongoDB技术(一)
|
1月前
|
NoSQL Cloud Native atlas
探索云原生数据库:MongoDB Atlas 的实践与思考
【10月更文挑战第21天】本文探讨了MongoDB Atlas的核心特性、实践应用及对云原生数据库未来的思考。MongoDB Atlas作为MongoDB的云原生版本,提供全球分布式、完全托管、弹性伸缩和安全合规等优势,支持快速部署、数据全球化、自动化运维和灵活定价。文章还讨论了云原生数据库的未来趋势,如架构灵活性、智能化运维和混合云支持,并分享了实施MongoDB Atlas的最佳实践。
|
2月前
|
NoSQL Cloud Native atlas
探索云原生数据库:MongoDB Atlas 的实践与思考
【10月更文挑战第20天】本文探讨了MongoDB Atlas的核心特性、实践应用及对未来云原生数据库的思考。MongoDB Atlas作为云原生数据库服务,具备全球分布、完全托管、弹性伸缩和安全合规等优势,支持快速部署、数据全球化、自动化运维和灵活定价。文章还讨论了实施MongoDB Atlas的最佳实践和职业心得,展望了云原生数据库的发展趋势。
|
2月前
|
存储 NoSQL MongoDB
MongoDB 数据库引用
10月更文挑战第20天
22 1
|
2月前
|
存储 NoSQL Shell
MongoDB 创建数据库
10月更文挑战第12天
72 4
|
2月前
|
存储 NoSQL MongoDB
基于阿里云数据库MongoDB版,微财数科“又快又稳”服务超7000万客户
选择MongoDB主要基于其灵活的数据模型、高性能、高可用性、可扩展性、安全性和强大的分析能力。