mogndb 慢查询

0  摘要

  在MySQL中,慢查询日志是经常作为我们优化查询的依据,那在MongoDB中是否有类似的功能呢?答案是肯定的,那就是开启Profiling功能。该工具在运行的实例上收集有关MongoDB的写操作,游标,数据库命令等,可以在数据库级别开启该工具,也可以在实例级别开启。该工具会把收集到的所有都写入到system.profile集合中,该集合是一个capped collection。更多的信息见:http://docs.mongodb.org/manual/tutorial/manage-the-database-profiler/

  1  慢查询分析流程

 

   慢查询日志一般作为优化步骤里的第一步。通过慢查询日志,定位每一条语句的查询时间。比如超过了200ms,那么查询超过200ms的语句需要优化。然后它通过 .explain() 解析影响行数是不是过大,所以导致查询语句超过200ms。

   所以优化步骤一般就是:

    1.用慢查询日志(system.profile)找到超过200ms的语句

    2.然后再通过.explain()解析影响行数,分析为什么超过200ms 

    3.决定是不是需要添加索引

  2  开启慢查询

2.1  Profiling级别说明

1
2
3
0:关闭,不收集任何数据。
1:收集慢查询数据,默认是100毫秒。
2:收集所有数据

2.2  开启Profiling和设置

1:通过mongo shell:

   需要进入server 

   mongo 而不是路由器mongoos

1
2
3
4
5
6
7
8
9
10
11
12
#查看状态:级别和时间
PRIMARY> db.getProfilingStatus()
"was" : 1, "slowms" : 200 }
#查看级别
PRIMARY> db.getProfilingLevel()
1
#设置级别
PRIMARY> db.setProfilingLevel(2)
"was" : 1, "slowms" : 100, "ok" : 1 }
#设置级别和时间
PRIMARY> db.setProfilingLevel(1,200)
"was" : 2, "slowms" : 100, "ok" : 1 }

注意:

  1  以上要操作要是在test集合下面的话,只对该集合里的操作有效,要是需要对整个实例有效,则需要在所有的集合下设置或则在开启的时候开启参数

  2 每次设置之后返回给你的结果是修改之前的状态(包括级别、时间参数)。

 

2:不通过mongo shell:

在mongoDB启动的时候

1
mongod --profile=1  --slowms=200

或则在配置文件里添加2行:

1
2
profile = 1
slowms = 200

3:关闭Profiling

1
2
3
# 关闭
PRIMARY> db.setProfilingLevel(0)
"was" : 1, "slowms" : 200, "ok" : 1 }

4:修改“慢查询日志”的大小

1
2
3
4
5
6
7
8
9
10
11
12
#关闭Profiling
PRIMARY> db.setProfilingLevel(0)
"was" : 0, "slowms" : 200, "ok" : 1 }
#删除system.profile集合
PRIMARY> db.system.profile.drop()
true
#创建一个新的system.profile集合 --- 4M
PRIMARY> db.createCollection( "system.profile", { capped: true, size:4000000 } )
"ok" : 1 }
#重新开启Profiling
PRIMARY> db.setProfilingLevel(1)
"was" : 0, "slowms" : 200, "ok" : 1 }

注意:要改变Secondary的system.profile的大小,你必须停止Secondary,运行它作为一个独立的mongodb,然后再执行上述步骤。完成后,重新启动加入副本集。

 

  2.3  Profile 效率

  Profiling功能肯定是会影响效率的,但是不太严重,原因是他使用的是system.profile 来记录,而system.profile 是一个capped collection, 这种collection 在操作上有一些限制和特点,但是效率更高。

3   慢查询(system.profile)分析

通过 db.system.profile.find() 查看当前所有的慢查询日志,下面的例子说明各个参数的含义,更多信息见:http://docs.mongodb.org/manual/reference /database-profiler/

 3.1:参数含义  -- (这是一个query 类型的 慢查询)

{"op" : "query",  #操作类型,有insert、query、update、remove、getmore、command   "ns" : "onroad.route_model", #操作的集合"query" : {"$query" : {"user_id" : 314436841,"data_time" : {"$gte" : 1436198400}},"$orderby" : {"data_time" : 1}},"ntoskip" : 0, #指定跳过skip()方法 的文档的数量。"nscanned" : 2, #为了执行该操作,MongoDB在 index 中浏览的文档数。 一般来说,如果 nscanned 值高于 nreturned 的值,说明数据库为了找到目标文档扫描了很多文档。这时可以考虑创建索引来提高效率。"nscannedObjects" : 1,  #为了执行该操作,MongoDB在 collection中浏览的文档数。"keyUpdates" : 0, #索引更新的数量,改变一个索引键带有一个小的性能开销,因为数据库必须删除旧的key,并插入一个新的key到B-树索引"numYield" : 1,  #该操作为了使其他操作完成而放弃的次数。通常来说,当他们需要访问还没有完全读入内存中的数据时,操作将放弃。这使得在MongoDB为了放弃操作进行数据读取的同时,还有数据在内存中的其他操作可以完成"lockStats" : {  #锁信息,R:全局读锁;W:全局写锁;r:特定数据库的读锁;w:特定数据库的写锁"timeLockedMicros" : {  #该操作获取一个级锁花费的时间。对于请求多个锁的操作,比如对 local 数据库锁来更新 oplog ,该值比该操作的总长要长(即 millis )"r" : NumberLong(1089485),"w" : NumberLong(0)},"timeAcquiringMicros" : {  #该操作等待获取一个级锁花费的时间。"r" : NumberLong(102),"w" : NumberLong(2)}},"nreturned" : 1,  // 返回的文档数量"responseLength" : 1669, // 返回字节长度,如果这个数字很大,考虑值返回所需字段"millis" : 544, #消耗的时间(毫秒)"execStats" : {  #一个文档,其中包含执行 查询 的操作,对于其他操作,这个值是一个空文件, system.profile.execStats 显示了就像树一样的统计结构,每个节点提供了在执行阶段的查询操作情况。"type" : "LIMIT", ##使用limit限制返回数  "works" : 2,"yields" : 1,"unyields" : 1,"invalidates" : 0,"advanced" : 1,"needTime" : 0,"needFetch" : 0,"isEOF" : 1,  #是否为文件结束符"children" : [{"type" : "FETCH",  #根据索引去检索指定document"works" : 1,"yields" : 1,"unyields" : 1,"invalidates" : 0,"advanced" : 1,"needTime" : 0,"needFetch" : 0,"isEOF" : 0,"alreadyHasObj" : 0,"forcedFetches" : 0,"matchTested" : 0,"children" : [{"type" : "IXSCAN", #扫描索引键"works" : 1,"yields" : 1,"unyields" : 1,"invalidates" : 0,"advanced" : 1,"needTime" : 0,"needFetch" : 0,"isEOF" : 0,"keyPattern" : "{ user_id: 1.0, data_time: -1.0 }","boundsVerbose" : "field #0['user_id']: [314436841, 314436841], field #1['data_time']: [1436198400, inf.0]","isMultiKey" : 0,"yieldMovedCursor" : 0,"dupsTested" : 0,"dupsDropped" : 0,"seenInvalidated" : 0,"matchTested" : 0,"keysExamined" : 2,"children" : [ ]}]}]},"ts" : ISODate("2015-10-15T07:41:03.061Z"), #该命令在何时执行"client" : "10.10.86.171", #链接ip或则主机"allUsers" : [{"user" : "martin_v8","db" : "onroad"}],"user" : "martin_v8@onroad"
}

 

 

 3.2: 分析

如果发现 millis 值比较大,那么就需要作优化。

1  如果nscanned数很大,或者接近记录总数(文档数),那么可能没有用到索引查询,而是全表扫描。

2  如果 nscanned 值高于 nreturned 的值,说明数据库为了找到目标文档扫描了很多文档。这时可以考虑创建索引来提高效率。

 3.3  system.profile补充

‘type’的返回参数说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
COLLSCAN #全表扫描
IXSCAN #索引扫描
FETCH #根据索引去检索指定document
SHARD_MERGE #将各个分片返回数据进行merge
SORT #表明在内存中进行了排序(与老版本的scanAndOrder:true一致)
LIMIT #使用limit限制返回数
SKIP #使用skip进行跳过
IDHACK #针对_id进行查询
SHARDING_FILTER #通过mongos对分片数据进行查询
COUNT #利用db.coll.explain().count()之类进行count运算
COUNTSCAN #count不使用Index进行count时的stage返回
COUNT_SCAN #count使用了Index进行count时的stage返回
SUBPLA #未使用到索引的$or查询的stage返回
TEXT #使用全文索引进行查询时候的stage返回
PROJECTION #限定返回字段时候stage的返回

对于普通查询,我们最希望看到的组合有这些:

1
2
3
4
5
6
Fetch+IDHACK
Fetch+ixscan
Limit+(Fetch+ixscan)
PROJECTION+ixscan
SHARDING_FILTER+ixscan

不希望看到包含如下的type:

1
COLLSCAN(全表扫),SORT(使用sort但是无index),不合理的SKIP,SUBPLA(未用到index的$or)

对于count查询,希望看到的有:

1
COUNT_SCAN

不希望看到的有:

1
COUNTSCAN

 

4  性能(explain)分析

 

SECONDARY> db.route_model.find({ "user_id" : 313830621, "data_time" : { "$lte" : 1443715200, "$gte" : 1443542400 } }).explain()
{"cursor" : "BtreeCursor user_id_1_data_time_-1",  #返回游标类型,有BasicCursor和BtreeCursor,后者意味着使用了索引。"isMultiKey" : false,"n" : 23, #返回的文档行数。"nscannedObjects" : 23,  #这是MongoDB按照索引指针去磁盘上查找实际文档的次数。如果查询包含的查询条件不是索引的一部分,或者说要求返回不在索引内的字段,MongoDB就必须依次查找每个索引条目指向的文档。"nscanned" : 23,  #如果有使用索引,那么这个数字就是查找过的索引条目数量,如果本次查询是一次全表扫描,那么这个数字就代表检查过的文档数目"nscannedObjectsAllPlans" : 46,"nscannedAllPlans" : 46,"scanAndOrder" : false,  #MongoDB是否在内存中对结果集进行了排序"indexOnly" : false, #MongoDB是否只使用索引就能完成此次查询"nYields" : 1,  #为了让写入请求能够顺利执行,本次查询暂停暂停的次数。如果有写入请求需求处理,查询会周期性的释放他们的锁,以便写入能够顺利执行"nChunkSkips" : 0,"millis" : 1530,  #数据库执行本次查询所耗费的毫秒数。这个数字越小,说明效率越高"indexBounds" : {  #这个字段描述了索引的使用情况,给出了索引的遍历范围"user_id" : [[313830621,313830621]],"data_time" : [[1443715200,1443542400]]},"server" : "a7cecd4f9295:27017","filterSet" : false,"stats" : {"type" : "FETCH","works" : 25,"yields" : 1,"unyields" : 1,"invalidates" : 0,"advanced" : 23,"needTime" : 0,"needFetch" : 0,"isEOF" : 1,"alreadyHasObj" : 0,"forcedFetches" : 0,"matchTested" : 0,"children" : [{"type" : "IXSCAN",#这里使用了索引"works" : 23,"yields" : 1,"unyields" : 1,"invalidates" : 0,"advanced" : 23,"needTime" : 0,"needFetch" : 0,"isEOF" : 1,"keyPattern" : "{ user_id: 1.0, data_time: -1.0 }","boundsVerbose" : "field #0['user_id']: [313830621.0, 313830621.0], field #1['data_time']: [1443715200.0, 1443542400.0]","isMultiKey" : 0,"yieldMovedCursor" : 0,"dupsTested" : 0,"dupsDropped" : 0,"seenInvalidated" : 0,"matchTested" : 0,"keysExamined" : 23,"children" : [ ]}]}
}

详细解释 : https://docs.mongodb.org/manual/reference/database-profiler/

这里的分析类似于 system.profile 

5  日常使用的慢日志(system.profile)查询

 

#返回最近的10条记录

1
db.system.profile.find().limit(10).sort({ ts : -1 }).pretty()

#返回所有的操作,除command类型的

1
db.system.profile.find( { op: { $ne : ‘command‘ } }).pretty()

#返回特定集合

1
db.system.profile.find( { ns : ‘mydb.test‘ } ).pretty()

#返回大于5毫秒慢的操作

1
db.system.profile.find({ millis : { $gt : 5 } } ).pretty()

#从一个特定的时间范围内返回信息

1
2
3
4
5
6
7
8
db.system.profile.find(
                      {
                       ts : {
                             $gt : new ISODate("2015-10-18T03:00:00Z"),
                             $lt : new ISODate("2015-10-19T03:40:00Z")
                            }
                      }
                     ).pretty()

#特定时间,限制用户,按照消耗时间排序

1
2
3
4
5
6
7
8
9
db.system.profile.find(
                      {
                        ts : {
                              $gt : newISODate("2015-10-12T03:00:00Z") ,
                              $lt : newISODate("2015-10-12T03:40:00Z")
                             }
                      },
                      { user : 0 }
                     ).sort( { millis : -1 } )

#查看最新的 Profile  记录: 

1
db.system.profile.find().sort({$natural:-1}).limit(1)

# 显示5个最近的事件

1
show profile

6  对慢查询语句建索引

     详细请见下一篇博文

转载于:https://www.cnblogs.com/williamjie/p/9641401.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/464999.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux命令中正则表达式的运用

一、正则表达式简介 事实上,正则表达式不仅适用于linux,多种编程语言中也可以使用到它,因为它实际上是人们对于某种规律的表达方式。 如果要把他的所有应用都讲上的话那这篇文章会变的太长以至于无法阅读,我只介绍他在linux下和几…

程序的内存分配模式(堆栈以及静态存储区,文字常量区,代码区)

程序的内存分配模式 一个由 C/C编译的程序占用的内存分为以下几个部分: 1、栈区( stack )—由编译器自动分配释放,存放函数的参数值,局部变量的值 等。其操作方式类似于数据结构中的栈。 2、堆区( heap&a…

稚晖君教你制作全球最迷你的自平衡机器人

摘要:Nano是一个小巧可爱的机器人,身高大约10公分,特点是平衡感好,长得很白以及善于卖萌。作为全球最迷你的自平衡机器人,Nano身材虽小,但配置有丰富的传感器—陀螺仪,超声波,Motion…

9.13作业

2、python test.py执行的三个阶段是什么?在哪个阶段识别文件内的python语法? 先运行python解释器,将python文件从硬盘读取到内存,解释执行内存读取的代码,开始识别python语法。 在第3个阶段识别文件内的python语法 3、…

tomcat 6.0环境, 网页超链接,文件下载另存为时,不能识别msi文件类型,另存为只能选htm和所有文件。...

问题: tomcat 6.0环境&#xff0c; 网页超链接&#xff0c;文件下载另存为时&#xff0c;不能识别msi文件类型&#xff0c;另存为只能选htm和所有文件。 解决办法:在 ...\Tomcat 6.0\conf 文件夹下的 web.xml 文件中添加以下类型声明:<mime-mapping><extension>msi…

ARM不同位数系统int字节数区别

32位和64位系统区别及int字节数 一&#xff09;64位系统和32位有什么区别&#xff1f; 1、64bit CPU拥有更大的寻址能力&#xff0c;最大支持到16GB内存&#xff0c;而32bit只支持4G内存 2、64位CPU一次可提取64位数据&#xff0c;比32位提高了一倍&#xff0c;理论上性能会…

我的广州大伯

2021年11月24日我正在办公室和同事调试项目&#xff0c;突然接到我婶的微信语音电话&#xff0c;我婶说广州的大伯过世了&#xff0c;他们现在正在去大伯家的路上。我大伯是爷爷奶奶最大的儿子&#xff0c;爷爷奶奶在世时&#xff0c;家里的很多事情&#xff0c;都会和大伯商量…

VUE 入坑系列 一 双向绑定

html代码<div id"app"><p>{{message}}</p><span>message1</span> <input v-model"message"><span>message2</span> <input v-model"message"></div> View Codejavascript代码var …

semihost/ITM机制浅析以及使用JLINK通过ITM调试stm32单片机

使用ITM机制实现调试stm32单片机&#xff0c;实现printf与scanf。 ITM简介 ITM机制是一种调试机制&#xff0c;是新一代调试方式&#xff0c;在这之前&#xff0c;有一种比较出名的调试方式&#xff0c;称为半主机&#xff08;semihosting&#xff09;方式。 在pc上编写过C语…

spring+ibatis配置

spring-dao.xml配置 <bean id"sqlMapClient" class"org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name"configLocation" value"classpath:/sql-map-config.xml"/> <property…

5毛钱搞一个2.4GHz射频信号探测器

射频电子领域神秘而又朦胧&#xff0c;今天我们通过一个小小的射频检波电路来体验一下射频世界的魅力。实验目的制作一个 2.4 GHz 射频信号探测器&#xff0c;电路简单总成本不到 5 毛钱。该电路在靠近 2.4 GHz 无线信号时 LED 灯会闪烁。这是我用制作好的 2.4 GHz 射频信号靠近…

华为宣布:免费培养8000名嵌入式开发者!学习免费!实践免费!辅导免费!

真正的5G时代&#xff0c;万物互联各行各业都离不开智能物联网技术物联网 (IoT) 设备会生成海量数据通过分析这些数据可以提供业务洞察力优化业务决策&#xff0c;实现流程自动化也由于物联网的迅速兴起&#xff0c;专业性人才稀缺各阶层课程层出不穷&#xff0c;开发者眼花缭乱…

关于××× 相关收集资料

1、服务&#xff1a; 那要建立一个必需要什么条件呢&#xff1f; 第一&#xff1a;服务器要有一个固定的外网IP地址。 第二&#xff1a;服务器至少要有两张网卡&#xff0c;来接口和内部网的通信。 当有了这样的条件&#xff0c;我们就可以来建立一台服务器了。转载于:https://…

现在不要着急买房

我写这篇文章&#xff0c;是因为确实最近有人向我咨询买房的事&#xff0c;今天抽空想聊下这方面的事&#xff0c;如果观点不正确&#xff0c;欢迎评论说出你的想法。是前天&#xff0c;我一个同学咨询我买房的事情。我也直接说了&#xff0c;最近两年&#xff0c;把钱放在口袋…

解决vlc-android播放http视频退出问题

之前用vlc-android播放http视频,程序就自动退出了,尝试用ndk-gdb调试,但是一调试,就报 /home/administrator/code/vlc-android/extras/package/android/vlc-android/obj/local/armeabi/gdb.setup:4: Error in sourced command file:Remote communication error: Connection res…

受保护的属性无法直接读取

转载于:https://www.cnblogs.com/xiaobiaomei/p/9645795.html

MDK530编译出现ARM版本不符问题

1、用最新版的MDK530编译原来的代码出现问题&#xff1a;错误&#xff1a;“35; pragma import”是ARM编译器5的扩展&#xff0c;ARM编译器6不支持它[-Warmcc pragma import] 在仙女棒里面将ARM6修改为ARM5&#xff1a; 与此同时&#xff0c;在sys.c里面__asm void MSR_MSP(u3…

存储器Flash页、扇区、块的区别

作者 | strongerHuang微信公众号 | 嵌入式专栏大家都知道Flash是用于存储数据的存储器&#xff0c;但很多读者看到页(Page)、扇区(Sector)、块(Block)等这些单位时一脸懵逼&#xff0c;这到底是什么&#xff0c;有什么区别&#xff1f;下面就来讲讲关于Flash内部结构组织以及相…

volatile用法

许多程序员无法正确的理解C语言关键字volatile。这并不奇怪&#xff0c;大多数C原因书籍不过一两句一带而过。本文将告诉你如何正确使用它。 在C/C嵌入式代码中&#xff0c;你是否经历过下面的情况&#xff1a; ● 代码执行正常–直到你打开了编译器优化 ● 代码执行正常–直…

Java 删除ArrayList中重复元素,保持顺序

// 删除ArrayList中重复元素&#xff0c;保持顺序 public static List<Map<String, Object>> removeDuplicateWithOrder(List<Map<String, Object>> list) { Set<Map<String, Object>> set new HashSet<Map<St…