MongoDB使用profile分析慢查询的步骤


Posted in MongoDB onApril 30, 2021

      在MongoDB中,如果发生了慢查询,我们如何得到这些慢查询的语句,并优化呢?今天来看这块儿的一些心得。

01 如何收集慢查询?

    在MongoDB中,通常可以开启profile来收集慢日志,查看当前profile状态的语句如下:

test1:PRIMARY> db.getProfilingStatus()
{
        "was" : 2,
        "slowms" : 0,
        "sampleRate" : 1,
        "$gleStats" : {
                "lastOpTime" : Timestamp(0, 0),
                "electionId" : ObjectId("7fffffff0000000000000005")
        },
        "lastCommittedOpTime" : Timestamp(1619186976, 2),
        "$configServerState" : {
                "opTime" : {
                        "ts" : Timestamp(1619186976, 1),
                        "t" : NumberLong(2)
                }
        },
        "$clusterTime" : {
                "clusterTime" : Timestamp(1619186976, 2),
                "signature" : {
                        "hash" : BinData(0,"zvwFpgc0KFxieMpj7mBPdrOnonI="),
                        "keyId" : NumberLong("6904838687771590657")
                }
        },
        "operationTime" : Timestamp(1619186976, 2)
}

这里我们可以看到2个关键参数,分别是was和slowms,其中:

was=0,代表不记录任何的语句;

was=1,代表记录执行时间超过slowms的语句

was=2,代表记录所有的语句

slowms代表语句的阈值,单位是ms

上图中的结果代表我们的实例会收集所有的查询语句。profile收集的查询语句结果存放在admin数据库中的system.profile集合中,可以通过下面的方法进行访问:

test1:PRIMARY> use admin
switched to db admin

test1:PRIMARY> db.system.profile.find({'op':'query'},{'op':1,'ns':1,'millis':1,'ts':1})
{ "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:14.815Z") }
{ "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:15.139Z") }
{ "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:15.141Z") }
{ "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:15.239Z") }
{ "op" : "query", "ns" : "admin.system.version", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:16.155Z") }
{ "op" : "query", "ns" : "admin.system.version", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:16.192Z") }
{ "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:16.225Z") }
{ "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:16.273Z") }
{ "op" : "query", "ns" : "admin.system.version", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:16.276Z") }

02 system.profile慢查询集合分析

   admin数据库中的system.profile是一个固定集合,保存着超过设置的慢查询的结果。我们来看里面的一条慢查询。

    利用下面的方法,来拿到一条数据,并对其中的关键字段进行注释说明:

test1:PRIMARY> db.system.profile.findOne({'op':'query'})
{
        "op" : "query",  # 操作类型
        "ns" : "admin.system.users",  # 命名空间
        "command" : {
                "find" : "system.users",
                "filter" : {
                        "_id" : "admin.root"  # 过滤的字段
                },
                "limit" : 1,
                "singleBatch" : true,
                "lsid" : {
                        "id" : UUID("a6034f5e-77c1-4b19-9669-60e1253edf4b")
                },
                "$readPreference" : {
                        "mode" : "secondaryPreferred"
                },
                "$db" : "admin"
        },
        "keysExamined" : 1,   # 扫描的索引数
        "docsExamined" : 1,   # 扫描的行数
        "cursorExhausted" : true,  
        "numYield" : 0,
        "nreturned" : 1,   # 返回的值的行数
        "locks" : {
                xxxx   #  锁信息
        },
        "flowControl" : {

        },
        "storage" : {
        },
        "responseLength" : 647,
        "protocol" : "op_query",
        "millis" : 0,    # 这个查询的执行时间,因为我们设置的profilestatus是0,因此所有操作都被记录了。
        "planSummary" : "IDHACK",  # 针对_id进行查询
        "execStats" : {   # 查询执行状态
                "stage" : "IDHACK",
                "nReturned" : 1,
                "executionTimeMillisEstimate" : 0,
                "works" : 2,
                "advanced" : 1,
                "needTime" : 0,
                "needYield" : 0,
                "saveState" : 0,
                "restoreState" : 0,
                "isEOF" : 1,
                "keysExamined" : 1,
                "docsExamined" : 1
        },
        "ts" : ISODate("2020-08-27T07:22:14.815Z"),
        "client" : "xx.xx.xx.xx",  # 查询的客户端IP地址
        "allUsers" : [   #  所有的用户信息
                {
                        "user" : "root",
                        "db" : "admin"
                }
        ],
        "user" : "root@admin"   # 使用的用户信息
}

03 慢查询分析利器---explain

   通常情况下,我们可以使用MongoDB的explain语法来分析一个语句的查询性能,包含是否用到索引、扫描行数等信息,explain语法的基本用法:

后置写法
db.system.profile.find({'op':'query'}).explain()
前置写法
db.system.profile.explain().find({'op':'query'})

其中,explain可以放在查询语句的后面或者前面,当然find语法也可以是update、remove、insert

explain语法的输出分为3种不同的详细程度,分别如下:

三种清晰度模式,清晰度越高,则输出的信息越全,默认情况下是queryPlanner:

1、queryPlanner模式(默认)
db.products.explain().count( { quantity: { $gt: 50 } } )

2、executionStats模式
db.products.explain("executionStats").count( { quantity: { $gt: 50 } } )

3、allPlansExecution模式
db.products.explain("allPlansExecution").count( { quantity: { $gt: 50 } } )

其中,allPlansExecution模式输出的信息最多。

下面是一个explain语法的输出内容,查询的SQL如下:

db.getCollection('files').find(
{"cTime":{
           "$gte":ISODate("2021-04-18"),
           "$lt":ISODate("2021-04-19")
       }}).limit(1000).explain("allPlansExecution")

输出的结果如下:

{
        "queryPlanner" : {   # 代表查询的执行计划
                "plannerVersion" : 1,   # 版本号
                "namespace" : "fs.files",   # 查询的命名空间,也就是集合名称
                "indexFilterSet" : false,   # 是否使用了索引过滤,注意,它并不能判定是否使用了索引
                "parsedQuery" : {    # 查询语法解析树
                        "$and" : [
                                {
                                        "cTime" : {
                                                "$lt" : ISODate("2021-04-19T00:00:00Z")
                                        }
                                },
                                {
                                        "cTime" : {
                                                "$gte" : ISODate("2021-04-18T00:00:00Z")
                                        }
                                }
                        ]
                },
                "winningPlan" : {    # 最终选择的查询计划
                        "stage" : "LIMIT",   # 查询的阶段,很重要,下面详细介绍
                        "limitAmount" : 1000,   # 查询结果的limit值
                        "inputStage" : {
                                "stage" : "FETCH",
                                "inputStage" : {
                                        "stage" : "IXSCAN",  # 代表索引扫描
                                        "keyPattern" : {
                                                "cTime" : 1
                                        },
                                        "indexName" : "cTime_1",  #  索引名称
                                        "isMultiKey" : false,    # 下面4个字段都是索引类型分析
                                        "isUnique" : false,
                                        "isSparse" : false,
                                        "isPartial" : false,
                                        "indexVersion" : 1,
                                        "direction" : "forward",
                                        "indexBounds" : {
                                                "cTime" : [
                                                        "[new Date(1618704000000), new Date(1618790400000))"
                                                ]
                                        }
                                }
                        }
                },
                "rejectedPlans" : [ ]  # 候选的没被选中的查询计划
        },
        "serverInfo" : {
                "host" : "xxxx",
                "port" : 24999,
                "version" : "3.2.8",
                "gitVersion" : "ed70e33130c977bda0024c125b56d159573dbaf0"
        },
        "ok" : 1
}

首先解释下stage的几个阶段:

  1. COLLSCAN---全表扫描
  2. IXSCAN---索引扫描
  3. FETCH---根据索引去检索文档
  4. SHARD_MERGE---合并分片结果
  5. IDHACK---针对id进行查询
  6. LIMIT---执行limit

了解了这些stage的阶段之后,我们可以看到,一个查询的过程是一层一层解析的,所以可以看到,stage这个字段有嵌套的情况。winningPlan中的执行计划也是按照一层一层的顺序去执行:

1、先执行最内层的索引扫描(IXSCAN);

2、再执行外面的FETCH,根据索引去拿文档

3、执行最后一步的limit,取指定数目个结果返回给客户端

以上就是MongoDB profile分析慢查询的示例的详细内容,更多关于MongoDB profile分析慢查询的资料请关注三水点靠木其它相关文章!

MongoDB 相关文章推荐
MongoDB balancer的使用详解
Apr 30 MongoDB
MongoDB数据库的安装步骤
Jun 18 MongoDB
浅析MongoDB之安全认证
Jun 26 MongoDB
mongodb数据库迁移变更的解决方案
Sep 04 MongoDB
阿里云服务器部署mongodb的详细过程
Sep 04 MongoDB
MongoDB日志切割的三种方式总结
Sep 15 MongoDB
关于CentOS 8 搭建MongoDB4.4分片集群的问题
Oct 24 MongoDB
centos8安装MongoDB的详细过程
Oct 24 MongoDB
剖析后OpLog订阅MongoDB的数据变更就没那么难了
Feb 24 MongoDB
MongoDB数据库部署环境准备及使用介绍
Mar 21 MongoDB
SpringBoot集成MongoDB实现文件上传的步骤
Apr 18 MongoDB
详解MongoDB排序时内存大小限制与创建索引的注意事项
May 06 MongoDB
MongoDB balancer的使用详解
Apr 30 #MongoDB
MongoDB数据库的安装步骤
Jun 18 #MongoDB
MongoDB数据库常用的10条操作命令
Jun 18 #MongoDB
MongoDB 常用的crud操作语句
Jun 20 #MongoDB
MongoDB orm框架的注意事项及简单使用
Jun 20 #MongoDB
详解MongoDB的条件查询和排序
Jun 23 #MongoDB
SpringBoot整合MongoDB的实现步骤
Jun 23 #MongoDB
You might like
PHP的开合式多级菜单程序
2006/10/09 PHP
PHP购物车类Cart.class.php定义与用法示例
2016/07/20 PHP
PHP实现 APP端微信支付功能
2018/06/22 PHP
什么是PHP7中的孤儿进程与僵尸进程
2019/04/14 PHP
用javascript作一个通用向导说明
2011/08/30 Javascript
关于onScroll事件在IE6下每次滚动触发三次bug说明
2011/09/21 Javascript
js change,propertychange,input事件小议
2011/12/20 Javascript
解决js下referer兼容各大浏览器的方法
2014/11/03 Javascript
页面内容排序插件jSort使用方法
2015/10/10 Javascript
简单介绍JavaScript数据类型之隐式类型转换
2015/12/28 Javascript
jQuery过滤特殊字符及JS字符串转为数字
2016/05/26 Javascript
Bootstrap源码解读按钮(5)
2016/12/23 Javascript
在DWR中实现直接获取一个JAVA类的返回值的两种方法
2016/12/25 Javascript
js实现省份下拉菜单效果
2017/02/15 Javascript
微信小程序如何刷新当前界面的实现方法
2019/06/07 Javascript
vue keep-alive 动态删除组件缓存的例子
2019/11/04 Javascript
VUEX 数据持久化,刷新后重新获取的例子
2019/11/12 Javascript
python使用paramiko模块实现ssh远程登陆上传文件并执行
2014/01/27 Python
python 统计列表中不同元素的数量方法
2018/06/29 Python
Python 从相对路径下import的方法
2018/12/04 Python
PIP和conda 更换国内安装源的方法步骤
2020/09/21 Python
python实现图片素描效果
2020/09/26 Python
python爬虫快速响应服务器的做法
2020/11/24 Python
Styleonme中文网:韩国高档人气品牌
2017/06/21 全球购物
iKRIX意大利网上商店:男女豪华服装和配件
2019/10/09 全球购物
求职简历中个人的自我评价
2013/12/25 职场文书
个人评价范文分享
2014/01/11 职场文书
学习委员自我鉴定
2014/01/13 职场文书
高三体育教学反思
2014/01/29 职场文书
“九一八事变纪念日”国旗下讲话稿
2014/09/14 职场文书
社区工作者个人总结
2015/02/28 职场文书
清洁工个人工作总结
2015/03/05 职场文书
忠犬八公的故事观后感
2015/06/05 职场文书
2015年幼师个人工作总结
2015/10/15 职场文书
2016学校先进集体事迹材料
2016/02/29 职场文书
MySQL 服务和数据库管理
2021/11/11 MySQL