• 售前

  • 售后

热门帖子
入门百科

MongoDB利用profile分析慢查询的步调

[复制链接]
123456809 显示全部楼层 发表于 2021-8-14 14:37:09 |阅读模式 打印 上一主题 下一主题
目录


  • 01 怎样收集慢查询?
  • 02 system.profile慢查询聚集分析
  • 03 慢查询分析利器---explain
      在MongoDB中,如果发生了慢查询,我们怎样得到这些慢查询的语句,并优化呢?本日来看这块儿的一些心得。

01 怎样收集慢查询?

    在MongoDB中,通常可以开启profile来收集慢日记,查看当前profile状态的语句如下:
  1. test1:PRIMARY> db.getProfilingStatus()
  2. {
  3.         "was" : 2,
  4.         "slowms" : 0,
  5.         "sampleRate" : 1,
  6.         "$gleStats" : {
  7.                 "lastOpTime" : Timestamp(0, 0),
  8.                 "electionId" : ObjectId("7fffffff0000000000000005")
  9.         },
  10.         "lastCommittedOpTime" : Timestamp(1619186976, 2),
  11.         "$configServerState" : {
  12.                 "opTime" : {
  13.                         "ts" : Timestamp(1619186976, 1),
  14.                         "t" : NumberLong(2)
  15.                 }
  16.         },
  17.         "$clusterTime" : {
  18.                 "clusterTime" : Timestamp(1619186976, 2),
  19.                 "signature" : {
  20.                         "hash" : BinData(0,"zvwFpgc0KFxieMpj7mBPdrOnonI="),
  21.                         "keyId" : NumberLong("6904838687771590657")
  22.                 }
  23.         },
  24.         "operationTime" : Timestamp(1619186976, 2)
  25. }
复制代码
这里我们可以看到2个关键参数,分别是was和slowms,此中:
was=0,代表不记录任何的语句;
was=1,代表记录实行时间凌驾slowms的语句
was=2,代表记录全部的语句
slowms代表语句的阈值,单元是ms
上图中的结果代表我们的实例会收集全部的查询语句。profile收集的查询语句结果存放在admin数据库中的system.profile聚会合,可以通过下面的方法进行访问:
  1. test1:PRIMARY> use admin
  2. switched to db admin
  3. test1:PRIMARY> db.system.profile.find({'op':'query'},{'op':1,'ns':1,'millis':1,'ts':1})
  4. { "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:14.815Z") }
  5. { "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:15.139Z") }
  6. { "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:15.141Z") }
  7. { "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:15.239Z") }
  8. { "op" : "query", "ns" : "admin.system.version", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:16.155Z") }
  9. { "op" : "query", "ns" : "admin.system.version", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:16.192Z") }
  10. { "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:16.225Z") }
  11. { "op" : "query", "ns" : "admin.system.users", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:16.273Z") }
  12. { "op" : "query", "ns" : "admin.system.version", "millis" : 0, "ts" : ISODate("2020-08-27T07:22:16.276Z") }
复制代码
02 system.profile慢查询聚集分析

   admin数据库中的system.profile是一个固定聚集,保存着凌驾设置的慢查询的结果。我们来看内里的一条慢查询。
    使用下面的方法,来拿到一条数据,并对此中的关键字段进行表明阐明:
  1. test1:PRIMARY> db.system.profile.findOne({'op':'query'})
  2. {
  3.         "op" : "query",  # 操作类型
  4.         "ns" : "admin.system.users",  # 命名空间
  5.         "command" : {
  6.                 "find" : "system.users",
  7.                 "filter" : {
  8.                         "_id" : "admin.root"  # 过滤的字段
  9.                 },
  10.                 "limit" : 1,
  11.                 "singleBatch" : true,
  12.                 "lsid" : {
  13.                         "id" : UUID("a6034f5e-77c1-4b19-9669-60e1253edf4b")
  14.                 },
  15.                 "$readPreference" : {
  16.                         "mode" : "secondaryPreferred"
  17.                 },
  18.                 "$db" : "admin"
  19.         },
  20.         "keysExamined" : 1,   # 扫描的索引数
  21.         "docsExamined" : 1,   # 扫描的行数
  22.         "cursorExhausted" : true,  
  23.         "numYield" : 0,
  24.         "nreturned" : 1,   # 返回的值的行数
  25.         "locks" : {
  26.                 xxxx   #  锁信息
  27.         },
  28.         "flowControl" : {
  29.         },
  30.         "storage" : {
  31.         },
  32.         "responseLength" : 647,
  33.         "protocol" : "op_query",
  34.         "millis" : 0,    # 这个查询的执行时间,因为我们设置的profilestatus是0,因此所有操作都被记录了。
  35.         "planSummary" : "IDHACK",  # 针对_id进行查询
  36.         "execStats" : {   # 查询执行状态
  37.                 "stage" : "IDHACK",
  38.                 "nReturned" : 1,
  39.                 "executionTimeMillisEstimate" : 0,
  40.                 "works" : 2,
  41.                 "advanced" : 1,
  42.                 "needTime" : 0,
  43.                 "needYield" : 0,
  44.                 "saveState" : 0,
  45.                 "restoreState" : 0,
  46.                 "isEOF" : 1,
  47.                 "keysExamined" : 1,
  48.                 "docsExamined" : 1
  49.         },
  50.         "ts" : ISODate("2020-08-27T07:22:14.815Z"),
  51.         "client" : "xx.xx.xx.xx",  # 查询的客户端IP地址
  52.         "allUsers" : [   #  所有的用户信息
  53.                 {
  54.                         "user" : "root",
  55.                         "db" : "admin"
  56.                 }
  57.         ],
  58.         "user" : "root@admin"   # 使用的用户信息
  59. }
复制代码
03 慢查询分析利器---explain

   通常环境下,我们可以使用MongoDB的explain语法来分析一个语句的查询性能,包含是否用到索引、扫描行数等信息,explain语法的根本用法:
  1. 后置写法
  2. db.system.profile.find({'op':'query'}).explain()
  3. 前置写法
  4. db.system.profile.explain().find({'op':'query'})
复制代码
此中,explain可以放在查询语句的后面大概前面,固然find语法也可以是update、remove、insert
explain语法的输出分为3种差别的详细水平,分别如下:
三种清晰度模式,清晰度越高,则输出的信息越全,默认环境下是queryPlanner:
  1. 1、queryPlanner模式(默认)
  2. db.products.explain().count( { quantity: { $gt: 50 } } )
  3. 2、executionStats模式
  4. db.products.explain("executionStats").count( { quantity: { $gt: 50 } } )
  5. 3、allPlansExecution模式
  6. db.products.explain("allPlansExecution").count( { quantity: { $gt: 50 } } )
复制代码
此中,allPlansExecution模式输出的信息最多。
下面是一个explain语法的输出内容,查询的SQL如下:
  1. db.getCollection('files').find(
  2. {"cTime":{
  3.            "$gte":ISODate("2021-04-18"),
  4.            "$lt":ISODate("2021-04-19")
  5.        }}).limit(1000).explain("allPlansExecution")
复制代码
输出的结果如下:
  1. {
  2.         "queryPlanner" : {   # 代表查询的执行计划
  3.                 "plannerVersion" : 1,   # 版本号
  4.                 "namespace" : "fs.files",   # 查询的命名空间,也就是集合名称
  5.                 "indexFilterSet" : false,   # 是否使用了索引过滤,注意,它并不能判定是否使用了索引
  6.                 "parsedQuery" : {    # 查询语法解析树
  7.                         "$and" : [
  8.                                 {
  9.                                         "cTime" : {
  10.                                                 "$lt" : ISODate("2021-04-19T00:00:00Z")
  11.                                         }
  12.                                 },
  13.                                 {
  14.                                         "cTime" : {
  15.                                                 "$gte" : ISODate("2021-04-18T00:00:00Z")
  16.                                         }
  17.                                 }
  18.                         ]
  19.                 },
  20.                 "winningPlan" : {    # 最终选择的查询计划
  21.                         "stage" : "LIMIT",   # 查询的阶段,很重要,下面详细介绍
  22.                         "limitAmount" : 1000,   # 查询结果的limit值
  23.                         "inputStage" : {
  24.                                 "stage" : "FETCH",
  25.                                 "inputStage" : {
  26.                                         "stage" : "IXSCAN",  # 代表索引扫描
  27.                                         "keyPattern" : {
  28.                                                 "cTime" : 1
  29.                                         },
  30.                                         "indexName" : "cTime_1",  #  索引名称
  31.                                         "isMultiKey" : false,    # 下面4个字段都是索引类型分析
  32.                                         "isUnique" : false,
  33.                                         "isSparse" : false,
  34.                                         "isPartial" : false,
  35.                                         "indexVersion" : 1,
  36.                                         "direction" : "forward",
  37.                                         "indexBounds" : {
  38.                                                 "cTime" : [
  39.                                                         "[new Date(1618704000000), new Date(1618790400000))"
  40.                                                 ]
  41.                                         }
  42.                                 }
  43.                         }
  44.                 },
  45.                 "rejectedPlans" : [ ]  # 候选的没被选中的查询计划
  46.         },
  47.         "serverInfo" : {
  48.                 "host" : "xxxx",
  49.                 "port" : 24999,
  50.                 "version" : "3.2.8",
  51.                 "gitVersion" : "ed70e33130c977bda0024c125b56d159573dbaf0"
  52.         },
  53.         "ok" : 1
  54. }
复制代码
首先表明下stage的几个阶段:
       
  • COLLSCAN---全表扫描   
  • IXSCAN---索引扫描   
  • FETCH---根据索引去检索文档   
  • SHARD_MERGE---合并分片结果   
  • IDHACK---针对id进行查询   
  • LIMIT---实行limit
了解了这些stage的阶段之后,我们可以看到,一个查询的过程是一层一层剖析的,以是可以看到,stage这个字段有嵌套的环境。winningPlan中的实行操持也是按照一层一层的序次去实行:
1、先实行最内层的索引扫描(IXSCAN);
2、再实行外貌的FETCH,根据索引去拿文档
3、实行末了一步的limit,取指定数目个结果返回给客户端
以上就是MongoDB profile分析慢查询的示例的详细内容,更多关于MongoDB profile分析慢查询的资料请关注草根技术分享其它干系文章!

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作