zoukankan      html  css  js  c++  java
  • mongodb查询操作分析

    背景

    mongodb 提供了类sql的数据查询及操作方式,同时也包含了聚合操作、索引等多个机制;
    按以往的经验,不当的库表操作或索引模式往往会造成许多问题,如查询操作缓慢、数据库吞吐量低下、CPU或磁盘IO飙升等问题。
    因此在应用开发过程中,有必要对DB操作进行审视,尤其是关键业务或复杂条件查询。mongodb 提供了explain方法可以让我们
    对 DB查询语句进行分析,提前分析潜在的瓶颈。

    查询计划

    mongodb 通过查询计划(QueryPlan)描述一个查询语句的执行过程,而通常一个查询操作可能对应多组查询计划。
    这些查询计划通过选举机制产生最优计划,作为最终的执行方案。此外mongodb 还提供了查询计划的缓存机制,如下图:

    https://docs.mongodb.com/manual/_images/query-planner-diagram.bakedsvg.sv

    Diagram of query planner logic

    查询操作被映射到一个查询模型(query shape),模型中会包含条件(predicate)、排序(sort)、投影(projection)的定义;
    以查询模型作为Key查找已存在的Plan缓存,在找到缓存的下一步仍进一步评估查询性能,若性能评估结果未达标,则 mongodb会淘汰缓存并进入查询计划生成阶段。
    每一个计划生成阶段都会包含:

    • 产生候选计划;
    • 评估优选计划;
    • 竞选最优计划;
    • 创建缓存;

    在产生最优计划之后,查询执行器将执行当前计划并产生最终结果。

    explain 操作

    通过下面的语句,可以对当前查询计划展开分析

    db.T_FooData.find({
    "appId":"s5WrMmrJV_8RBJG17FSVoY995Kga",
    "nodeType":"SENSOR",
    "creationTime":{
        $gte : ISODate("2017-08-08T10:34:33.125Z"),
        $lt : ISODate("2017-08-08T12:34:33.125Z")
        }
    }).explain("executionStats")
    

    输出结果

    {
        "queryPlanner" : {
            "plannerVersion" : 1,
            "namespace" : "db.T_FooData",
            "indexFilterSet" : false,
            "parsedQuery" : {
                "$and" : [
                    {
                        "appId" : {
                            "$eq" : "s5WrMmrJV_8RBJG17FSVoY995Kga"
                        }
                    },
                    {
                        "nodeType" : {
                            "$eq" : "SENSOR"
                        }
                    },
                    {
                        "creationTime" : {
                            "$lt" : ISODate("2017-08-08T12:34:33.125Z")
                        }
                    },
                    {
                        "creationTime" : {
                            "$gte" : ISODate("2017-08-08T10:34:33.125Z")
                        }
                    }
                ]
            },
            "winningPlan" : { ... },
            "rejectedPlans" : [ ... ],
        },
        "executionStats" : {
            "executionSuccess" : true,
            "nReturned" : 62848,
            "executionTimeMillis" : 3058,
            "totalKeysExamined" : 1510833,
            "totalDocsExamined" : 1510833,
            "executionStages" : { ... }
    
        },
        "serverInfo" : {
            "host" : "NB3000W_MongoDB_01",
            "port" : 50001,
            "version" : "3.4.7",
            "gitVersion" : "4249c1d2b5999ebbf1fdf3bc0e0e3b3ff5c0aaf2"
        },
        "ok" : 1,
        "$gleStats" : {
            "lastOpTime" : Timestamp(1504498101, 1),
            "electionId" : ObjectId("7fffffff0000000000000001")
        }
    }
    
    

    结果说明

    • queryPlanner 描述当前的查询计划;

    • queryPlanner.namespace 描述当前的集合命名空间,{db}.{collectionName}

    • queryPlanner.indexFilterSet 是否设置了indexFilter,Filter决定了查询优化器对于某个查询将如何使用索引

    • queryPlanner.parsedQuery 解析后的查询信息

    • queryPlanner.winningPlan 最优计划

    • queryPlanner.rejectPlans 拒绝的计划列表

    • executionStats 执行过程统计,捕获计划在执行过程中的相关信息

    • executionStats.executionSuccess 是否执行成功

    • executionStats.nReturned 返回条目数量

    • executionStats.executionTimeMilis 执行时间(ms)

    • executionStats.totalKeysExamined 索引检测条目

    • executionStats.totalDocsExamined 文档检测条目

    • executionStats.executionStages 执行阶段详情

    explain 模式

    mongodb 为 explain 操作提供了几种模式:

    • queryPlanner 默认的模式,仅进行查询计划分析,无法输出执行过程统计;
    • executionStats 执行模式,在查询计划分析后,将执行winningPlan并统计过程信息;
    • allPlansExecution 全计划执行模式,将执行所有计划(包括rejectPlans),并返回过程统计信息;
      executionStats.allPlansExecution 包含了所有计划(除winningPlan之外)的执行过程统计信息

    执行计划详解

    执行计划将整个过程分解为多个阶段,阶段(stage)以树状结构组织,这点与执行过程是匹配的。

    stage 分为多种类型,如下:

    阶段 描述
    COLLSCAN 全表扫描
    IXSCAN 索引扫描
    FETCH 根据索引去检索指定document
    PROJECTION 限定返回字段
    SHARD_MERGE 将各个分片返回数据进行merge
    SORT 表明在内存中进行了排序
    LIMIT 使用limit限制返回数
    SKIP 使用skip进行跳过
    IDHACK 针对_id进行查询
    SHARDING_FILTER 通过mongos对分片数据进行查询
    COUNT 利用db.coll.explain().count()之类进行count运算
    COUNTSCAN count不使用用Index进行count
    COUNT_SCAN count使用了Index进行count
    SUBPLA 未使用到索引的$or查询
    TEXT 使用全文索引进行查询

    winningPlan 样例

    "winningPlan" : {
                "stage" : "FETCH",
                "filter" : {
                    "$and" : [
                        {
                            "nodeType" : {
                                "$eq" : "GATEWAY"
                            }
                        },
                        {
                            "creationTime" : {
                                "$lt" : ISODate("2017-08-08T12:34:33.125Z")
                            }
                        },
                        {
                            "creationTime" : {
                                "$gte" : ISODate("2017-08-08T10:34:33.125Z")
                            }
                        }
                    ]
                },
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "keyPattern" : {
                        "appId" : 1
                    },
                    "indexName" : "appId",
                    "isMultiKey" : false,
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 1,
                    "direction" : "forward",
                    "indexBounds" : {
                        "appId" : [
                            "["s5WrMmrJV_8RBJG17FSVoY995Kga", "s5WrMmrJV_8RBJG17FSVoY995Kga"]"
                        ]
                    }
                }
            },
    

    字段说明

    属性 描述
    winningPlan.stage 最优计划stage,FETCH表示根据索引检索文档
    winningPlan.filter 最优计划的过滤器,即查询条件
    winningPlan.inputStage 最优计划stage的child stage
    winningPlan.inputStage.stage child stage,此处是IXSCAN,表示进行index scanning
    winningPlan.inputStage.keyPattern 扫描的索引模式
    winningPlan.inputStage.indexName 选用索引名称
    winningPlan.inputStage.isMultiKey 是否是Multikey,如果索引建立在array上则为true
    winningPlan.inputStage.isSparse 是否稀疏索引
    winningPlan.inputStage.isPartial 是否分区索引
    winningPlan.inputStage.direction 此query的查询顺序,此处是forward,如果用了.sort({w:-1})将显示backward
    winningPlan.inputStage.indexBounds 所扫描的索引范围

    过程统计详解

    executionStats 样例

    "executionStats" : {
            "executionSuccess" : true,
            "nReturned" : 62848,
            "executionTimeMillis" : 3058,
            "totalKeysExamined" : 1510833,
            "totalDocsExamined" : 1510833,
            "executionStages" : {
                "stage" : "FETCH",
                "filter" : {
                    "$and" : [
                        {
                            "nodeType" : {
                                "$eq" : "GATEWAY"
                            }
                        },
                        {
                            "creationTime" : {
                                "$lt" : ISODate("2017-08-08T12:34:33.125Z")
                            }
                        },
                        {
                            "creationTime" : {
                                "$gte" : ISODate("2017-08-08T10:34:33.125Z")
                            }
                        }
                    ]
                },
                "nReturned" : 62848,
                "executionTimeMillisEstimate" : 2765,
                "works" : 1510834,
                "advanced" : 62848,
                "needTime" : 1447985,
                "needYield" : 0,
                "saveState" : 11807,
                "restoreState" : 11807,
                "isEOF" : 1,
                "invalidates" : 0,
                "docsExamined" : 1510833,
                "alreadyHasObj" : 0,
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "nReturned" : 1510833,
                    "executionTimeMillisEstimate" : 792,
                    "works" : 1510834,
                    "advanced" : 1510833,
                    "needTime" : 0,
                    "needYield" : 0,
                    "saveState" : 11807,
                    "restoreState" : 11807,
                    "isEOF" : 1,
                    "invalidates" : 0,
                    "keyPattern" : {
                        "appId" : 1
                    },
                    "indexName" : "appId",
                    "isMultiKey" : false,
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 1,
                    "direction" : "forward",
                    "indexBounds" : {
                        "appId" : [
                            "["s5WrMmrJV_8RBJG17FSVoY995Kga", "s5WrMmrJV_8RBJG17FSVoY995Kga"]"
                        ]
                    },
                    "keysExamined" : 1510833,
                    "dupsTested" : 0,
                    "dupsDropped" : 0,
                    "seenInvalidated" : 0
                }
            }
    }
    

    字段说明

    属性 描述
    executionStats.executionSuccess 是否执行成功
    executionStats.nReturned 返回条目数量
    executionStats.executionTimeMilis 执行时间(ms)
    executionStats.totalKeysExamined 索引检测条目
    executionStats.totalDocsExamined 文档检测条目
    executionStats.executionStages 执行阶段详情,大部分字段继承于winningPlan.inputStage
    executionStats.executionStages.stage 执行阶段,FETCH表示根据索引获取文档
    executionStats.executionStages.nReturned 阶段返回条目数量
    executionStats.executionStages.executionTimeMillisEstimate 阶段执行时间
    executionStats.executionStages.docsExamined 阶段中文档检测条目
    executionStats.executionStages.works 阶段中扫描任务数
    executionStats.executionStages.advanced 阶段中向上提交数量
    executionStats.executionStages.needTime 阶段中定位索引位置所需次数
    executionStats.executionStages.needYield 阶段中获取锁等待时间
    executionStats.executionStages.isEOF 阶段中是否到达流的结束位,对于limit限制符的查询可能为0
    executionStats.executionStages.inputStage 执行阶段的子阶段,这里是一个IXSCAN的子过程

    参考文档

    explain 官方说明

    http://www.mongoing.com/eshu_explain1
    https://docs.mongodb.com/manual/reference/explain-results/#explain-output

    关于explain的几种模式
    https://docs.mongodb.com/manual/reference/method/cursor.explain/

    理解mongo 的查询行为
    https://www.compose.com/articles/explain-explain-understanding-mongo-query-behavior/

    mongo的查询缓存
    https://docs.mongodb.com/manual/core/query-plans/#index-filters

  • 相关阅读:
    对于动态建立索引的禁止方法
    在 Lotus Notes 中设置邮件定时发送的方法及代理功能介绍
    Lotus Domino中使用Xpage技术打造通讯录
    利用 LotusScript 实现 Microsoft Word 文档在公文流转中的公文留痕
    Ext.Template模板进阶
    Ext.template的使用
    Domino中Xpage和自定义控件的使用
    利用 LotusScript 灵活操作 Lotus Notes 富文本域
    ExtJs2.0学习系列(11)Ext.XTemplate
    利用 XForms 和 ODF 实现交互式办公文档
  • 原文地址:https://www.cnblogs.com/littleatp/p/8419678.html
Copyright © 2011-2022 走看看