mongodb查询操作分析

本文涉及的产品
云数据库 MongoDB,通用型 2核4GB
简介: 背景mongodb 提供了类sql的数据查询及操作方式,同时也包含了聚合操作、索引等多个机制;按以往的经验,不当的库表操作或索引模式往往会造成许多问题,如查询操作缓慢、数据库吞吐量低下、CPU或磁盘IO飙升等问题。

背景

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

查询计划

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

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

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

img_9b09a36f6de95886f52ce82fa1e89c88.jpe

作者: zale

出处: http://www.cnblogs.com/littleatp/, 如果喜欢我的文章,请关注我的公众号

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文链接  如有问题, 可留言咨询.

相关实践学习
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
目录
相关文章
|
4月前
|
NoSQL JavaScript 前端开发
如何使用 Node.js 连接和操作 MongoDB 数据库?
如何使用 Node.js 连接和操作 MongoDB 数据库?
227 2
|
3月前
|
NoSQL MongoDB Python
深入了解 Python MongoDB 操作:排序、删除、更新、结果限制全面解析
使用 sort() 方法对结果进行升序或降序排序。 sort() 方法接受一个参数用于“字段名”,一个参数用于“方向”(升序是默认方向)。
67 0
|
7月前
|
JSON NoSQL MongoDB
mongodb基本操作,增删改查,查询,索引,权限机制
mongodb基本操作,增删改查,查询,索引,权限机制
|
6月前
|
NoSQL MongoDB 索引
开心档-软件开发入门之MongoDB 覆盖索引查询
开心档-软件开发入门之MongoDB 覆盖索引查询
45 0
|
3月前
|
NoSQL 关系型数据库 MySQL
深入了解 Python MongoDB 查询:find 和 find_one 方法完全解析
在 MongoDB 中,我们使用 find() 和 find_one() 方法来在集合中查找数据,就像在MySQL数据库中使用 SELECT 语句来在表中查找数据一样
65 1
|
15天前
|
JSON NoSQL MongoDB
mongodb导出聚合查询的数据
mongodb导出聚合查询的数据
|
21天前
|
缓存 NoSQL 关系型数据库
【MongoDB】MongoDB更新操作时是否立刻fsync到磁盘?
【4月更文挑战第2天】【MongoDB】MongoDB更新操作时是否立刻fsync到磁盘?
|
22天前
|
消息中间件 NoSQL Kafka
云原生最佳实践系列 5:基于函数计算 FC 实现阿里云 Kafka 消息内容控制 MongoDB DML 操作
该方案描述了一个大数据ETL流程,其中阿里云Kafka消息根据内容触发函数计算(FC)函数,执行针对MongoDB的增、删、改操作。
|
3月前
|
机器学习/深度学习 自然语言处理 NoSQL
|
3月前
|
存储 NoSQL 安全
go 连接mongodb执行查询的代码
在Go语言中,你可以使用官方的MongoDB驱动程序 `"go.mongodb.org/mongo-driver/mongo"` 来连接MongoDB并执行查询。以下是一个简单的示例代码,演示如何连接MongoDB并执行查询: 首先,确保你已经安装了MongoDB驱动程序: ```bash go get go.mongodb.org/mongo-driver/mongo ``` 然后,可以使用以下示例代码: ```go package main import ( "context" "fmt" "log" "time" "go.mongodb.org/mongo-driv