• MongoDB分析工具之一:explain()语句分析工具


    explain(),语句分析工具

    MongoDB 3.0之后,explain的返回与使用方法与之前版本有了很大的变化,介于3.0之后的优秀特色和我们目前所使用给的是3.0.7版本,本文仅针对MongoDB 3.0+的explain进行讨论。3.0+的explain有三种模式,分别是:queryPlanner、executionStats、allPlansExecution。现实开发中,常用的是executionStats模式,主要分析这种模式。

     基本用法

    先来看一个基本用法:

    db.duan.find({x:1}).explain()

    explain()添加不同参数

    explain()也接收不同的参数,通过设置不同参数我们可以查看更详细的查询计划。

    • queryPlanner:queryPlanner是默认参数,添加queryPlanner参数的查询结果就是我们上面表格中看到的查询结果。
    • executionStats:executionStats会返回最佳执行计划的一些统计信息。
    • allPlansExecution:allPlansExecution用来获取所有执行计划,结果参数基本与上文相同。

    1、queryPlanner,这个是explain()默认参数

    直接跟在find()函数后面,表示查看find()函数的执行计划,结果如下:

    > db.duan.find({x:1}).explain()
    {
        "queryPlanner" : {
            "plannerVersion" : 1,
            "namespace" : "member_data.duan",
            "indexFilterSet" : false,
            "parsedQuery" : {
                "x" : {
                    "$eq" : 1
                }
            },
            "winningPlan" : {
                "stage" : "COLLSCAN",
                "filter" : {
                    "x" : {
                        "$eq" : 1
                    }
                },
                "direction" : "forward"
            },
            "rejectedPlans" : [ ]
        },
        "serverInfo" : {
            "host" : "localhost.localdomain",
            "port" : 27017,
            "version" : "4.0.6",
            "gitVersion" : "caa42a1f75a56c7643d0b68d3880444375ec42e3"
        },
        "ok" : 1
    }
    > 

    返回结果包含两大块信息,一个是queryPlanner,即查询计划,还有一个是serverInfo,即MongoDB服务的一些信息。那么这里涉及到的参数比较多,queryPlanner结果参数说明如下:

    参数                      
    含义                                                                                                       
    plannerVersion 查询计划版本
    namespace    要查询的集合(该值返回的是该query所查询的表)
    indexFilterSet    是否使用索引(针对该query是否有indexfilter)
    parsedQuery    查询条件,此处为x=1
    winningPlan    最佳执行计划
    winningPlan.stage   

    最优执行计划的stage(查询方式),常见的有:

    COLLSCAN/全表扫描:(应该知道就是CollectionScan,就是所谓的“集合扫描”,和mysql中table scan/heap scan类似,这个就是所谓的性能最烂最无奈的由来

    )、

    IXSCAN/索引扫描:(而是IndexScan,这就说明我们已经命中索引了)、

    FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询

    winningPlan.inputStage 用来描述子stage,并且为其父stage提供文档和索引关键字。
    winningPlan.stage的child stage 此处是IXSCAN,表示进行的是index scanning。
    winningPlan.keyPattern 所扫描的index内容,此处是did:1,status:1,modify_time: -1与scid : 1
    winningPlan.indexName winning plan所选用的index。
    winningPlan.isMultiKey 是否是Multikey,此处返回是false,如果索引建立在array上,此处将是true。
    winningPlan.direction 此query的查询顺序,此处是forward,如果用了.sort({modify_time:-1})将显示backward。
    filter    过滤条件
    winningPlan.indexBounds winningplan所扫描的索引范围,如果没有制定范围就是[MaxKey, MinKey],这主要是直接定位到mongodb的chunck中去查找数据,加快数据读取。
    rejectedPlans    拒绝的执行计划(其他执行计划(非最优而被查询优化器reject的)的详细返回,其中具体信息与winningPlan的返回中意义相同,故不在此赘述)      
    serverInfo    MongoDB服务器信息
       

    2、executionStats参数

    executionStats会返回最佳执行计划的一些统计信息,如下:

    > db.duan.find({x:1}).explain("executionStats")
    {
        "queryPlanner" : {
            "plannerVersion" : 1,
            "namespace" : "member_data.duan",
            "indexFilterSet" : false,
            "parsedQuery" : {
                "x" : {
                    "$eq" : 1
                }
            },
            "winningPlan" : {
                "stage" : "COLLSCAN",
                "filter" : {
                    "x" : {
                        "$eq" : 1
                    }
                },
                "direction" : "forward"
            },
            "rejectedPlans" : [ ]
        },
        "executionStats" : {
            "executionSuccess" : true,
            "nReturned" : 0,
            "executionTimeMillis" : 0,
            "totalKeysExamined" : 0,
            "totalDocsExamined" : 3,
            "executionStages" : {
                "stage" : "COLLSCAN",
                "filter" : {
                    "x" : {
                        "$eq" : 1
                    }
                },
                "nReturned" : 0,
                "executionTimeMillisEstimate" : 0,
                "works" : 5,
                "advanced" : 0,
                "needTime" : 4,
                "needYield" : 0,
                "saveState" : 0,
                "restoreState" : 0,
                "isEOF" : 1,
                "invalidates" : 0,
                "direction" : "forward",
                "docsExamined" : 3
            }
        },
        "serverInfo" : {
            "host" : "localhost.localdomain",
            "port" : 27017,
            "version" : "4.0.6",
            "gitVersion" : "caa42a1f75a56c7643d0b68d3880444375ec42e3"
        },
        "ok" : 1
    }
    > 
    这里除了我们上文介绍到的一些参数之外,还多了executionStats参数,含义如下:
    参数                      含义                                                                                                        
    executionSuccess    是否执行成功
    nReturned    返回的结果数
    executionTimeMillis    执行耗时
    totalKeysExamined    索引扫描次数
    totalDocsExamined    文档扫描次数
    executionStages    这个分类下描述执行的状态
    stage    扫描方式,具体可选值与上文的相同
    nReturned    查询结果数量
    executionTimeMillisEstimate    预估耗时
    works    工作单元数,一个查询会分解成小的工作单元
    advanced    优先返回的结果数
    docsExamined    文档检查数目,与totalDocsExamined一致。检查了总共的个documents,而从返回上面的nReturne数量
       
       

    常见用法:

        第一层,executionTimeMillis

        最为直观explain返回值是executionTimeMillis值,指的是我们这条语句的执行时间,这个值当然是希望越少越好。

        其中有3个executionTimeMillis,分别是:

        executionStats.executionTimeMillis

        该query的整体查询时间。

        executionStats.executionStages.executionTimeMillisEstimate

        该查询根据index去检索document获得2001条数据的时间。

        executionStats.executionStages.inputStage.executionTimeMillisEstimate

        该查询扫描2001行index所用时间。

        第二层,index与document扫描数与查询返回条目数

        这个主要讨论3个返回项,nReturned、totalKeysExamined、totalDocsExamined,分别代表该条查询返回的条目、索引扫描条目、文档扫描条目。

        这些都是直观地影响到executionTimeMillis,我们需要扫描的越少速度越快。

        对于一个查询,我们最理想的状态是:

        nReturned=totalKeysExamined=totalDocsExamined

        第三层,stage状态分析

        那么又是什么影响到了totalKeysExamined和totalDocsExamined?是stage的类型。类型列举如下:

        COLLSCAN:全表扫描

        IXSCAN:索引扫描

        FETCH:根据索引去检索指定document

        SHARD_MERGE:将各个分片返回数据进行merge

        SORT:表明在内存中进行了排序

        LIMIT:使用limit限制返回数

        SKIP:使用skip进行跳过

        IDHACK:针对_id进行查询

        SHARDING_FILTER:通过mongos对分片数据进行查询

        COUNT:利用db.coll.explain().count()之类进行count运算

        COUNTSCAN:count不使用Index进行count时的stage返回

        COUNT_SCAN:count使用了Index进行count时的stage返回

        SUBPLA:未使用到索引的$or查询的stage返回

        TEXT:使用全文索引进行查询时候的stage返回

        PROJECTION:限定返回字段时候stage的返回

        对于普通查询,我希望看到stage的组合(查询的时候尽可能用上索引):

        Fetch+IDHACK

        Fetch+ixscan

        Limit+(Fetch+ixscan)

        PROJECTION+ixscan

        SHARDING_FITER+ixscan

        COUNT_SCAN

    SORT_KEY_GENERATOR

        不希望看到包含如下的stage:

        COLLSCAN(全表扫描),SORT(使用sort但是无index),不合理的SKIP,SUBPLA(未用到index的$or),COUNTSCAN(不使用index进行count)

    3、allPlansExecution参数

    示例:

    > db.duan.find({x:1}).explain("allPlansExecution")
    {
        "queryPlanner" : {
            "plannerVersion" : 1,
            "namespace" : "member_data.duan",
            "indexFilterSet" : false,
            "parsedQuery" : {
                "x" : {
                    "$eq" : 1
                }
            },
            "winningPlan" : {
                "stage" : "COLLSCAN",
                "filter" : {
                    "x" : {
                        "$eq" : 1
                    }
                },
                "direction" : "forward"
            },
            "rejectedPlans" : [ ]
        },
        "executionStats" : {
            "executionSuccess" : true,
            "nReturned" : 0,
            "executionTimeMillis" : 0,
            "totalKeysExamined" : 0,
            "totalDocsExamined" : 3,
            "executionStages" : {
                "stage" : "COLLSCAN",
                "filter" : {
                    "x" : {
                        "$eq" : 1
                    }
                },
                "nReturned" : 0,
                "executionTimeMillisEstimate" : 0,
                "works" : 5,
                "advanced" : 0,
                "needTime" : 4,
                "needYield" : 0,
                "saveState" : 0,
                "restoreState" : 0,
                "isEOF" : 1,
                "invalidates" : 0,
                "direction" : "forward",
                "docsExamined" : 3
            },
            "allPlansExecution" : [ ]
        },
        "serverInfo" : {
            "host" : "localhost.localdomain",
            "port" : 27017,
            "version" : "4.0.6",
            "gitVersion" : "caa42a1f75a56c7643d0b68d3880444375ec42e3"
        },
        "ok" : 1
    }
    >

    聚合类的查询的explain()分析:

    db.getCollection('my_order').explain().aggregate([
            {$match: {"sender.id" : "8F8184E0ECF24B83980FE96357E7B746","status" : 1}},
            {$group:{_id:"$sender.id",totalAmount:{$sum:"$amount"},quantity:{$sum:1}}}        
    ])

    结果示例说明:

    {
            "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
    }
     
  • 相关阅读:
    JavaScript开发工具WebStorm v2022.2简体中文激活码
    分析J2SE和J2EE的Java剖析程序JProfiler
    Python判断Linux用户是否存在
    php连接MySQL数据库
    centos7镜像部署的phpfpm的9000端口无法被外部访问
    zabbix执行Python脚本报错error: import: command not found
    编译失败configure: error: Cannot find ldap libraries in /usr/lib
    PHP编译安装报错cannot stat `ext/phar/phar.phar': No such file or directory
    count(1)和count(*)的区别
    PHP编辑报错/lib64/liblber2.4.so.2: could not read symbols: Invalid operation
  • 原文地址:https://www.cnblogs.com/duanxz/p/3768253.html
Copyright © 2020-2023  润新知