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
總結
以上是生活随笔為你收集整理的mogndb 慢查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c/c++ 友元基本概念
- 下一篇: Photoshop英汉对照表