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使用profile分析慢查询的步骤
Apr 30 MongoDB
Mongo服务重启异常问题的处理方法
Jul 01 MongoDB
关于CentOS 8 搭建MongoDB4.4分片集群的问题
Oct 24 MongoDB
centos8安装MongoDB的详细过程
Oct 24 MongoDB
MongoDB连接数据库并创建数据等使用方法
Nov 27 MongoDB
SpringBoot 整合mongoDB并自定义连接池的示例代码
Feb 28 MongoDB
MongoDB数据库部署环境准备及使用介绍
Mar 21 MongoDB
mongoDB数据库索引快速入门指南
Mar 23 MongoDB
MongoDB误操作后使用oplog恢复数据
Apr 11 MongoDB
MongoDB支持的索引类型
Apr 11 MongoDB
MongoDB修改oplog大小的四种方法
Apr 11 MongoDB
NoSQL优缺点与MongoDB数据库简介
Jun 05 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获取文件内容最后一行示例
2014/01/09 PHP
windows下PHP_intl.dll正确配置方法(apache2.2+php5.3.5)
2014/01/14 PHP
PHP 面向对象程序设计(oop)学习笔记(三) - 单例模式和工厂模式
2014/06/12 PHP
深入解析PHP中SESSION反序列化机制
2017/03/01 PHP
php+mysql+jquery实现简易的检索自动补全提示功能
2017/04/15 PHP
Laravel学习教程之View模块详解
2017/09/18 PHP
laravel 框架配置404等异常页面
2019/01/07 PHP
php5.3/5.4/5.5/5.6/7常见新增特性汇总整理
2020/02/27 PHP
Javascript 实现的数独解题算法网页实例
2013/10/15 Javascript
JS获取URL中的参数数据
2013/12/05 Javascript
三种检测iPhone/iPad设备方向的方法
2014/04/23 Javascript
JS加载器如何动态加载外部js文件
2016/05/26 Javascript
利用angularjs1.4制作的简易滑动门效果
2017/02/28 Javascript
JavaScript 作用域scope简单汇总
2019/10/23 Javascript
浅谈VUE中演示v-for为什么要加key
2020/01/16 Javascript
uni-app微信小程序登录授权的实现
2020/05/22 Javascript
Python中为feedparser设置超时时间避免堵塞
2014/09/28 Python
Python实现的中国剩余定理算法示例
2017/08/05 Python
python3.x 将byte转成字符串的方法
2018/07/17 Python
python实现对指定字符串补足固定长度倍数截断输出的方法
2018/11/15 Python
Python设计模式之抽象工厂模式原理与用法详解
2019/01/15 Python
python实现几种归一化方法(Normalization Method)
2019/07/31 Python
Python内置函数property()如何使用
2020/09/01 Python
CSS3 3D制作实战案例分析
2016/09/18 HTML / CSS
大二学生学习个人自我评价
2014/01/19 职场文书
食堂个人先进事迹
2014/01/22 职场文书
运动会广播稿50字
2014/01/26 职场文书
党员岗位承诺书
2014/03/25 职场文书
大跃进口号
2014/06/16 职场文书
优秀党员自我评价范文
2014/09/15 职场文书
党员自评材料范文
2014/12/17 职场文书
卫生院义诊活动总结
2015/05/07 职场文书
政审证明材料
2015/06/19 职场文书
探究Mysql模糊查询是否区分大小写
2021/06/11 MySQL
详解Python requests模块
2021/06/21 Python
Java中Quartz高可用定时任务快速入门
2022/04/03 Java/Android