MongoDB使用profile分析慢查詢的步驟
在MongoDB中,如果發(fā)生了慢查詢,我們如何得到這些慢查詢的語句,并優(yōu)化呢?今天來看這塊兒的一些心得。
01 如何收集慢查詢?
在MongoDB中,通??梢蚤_啟profile來收集慢日志,查看當前profile狀態(tài)的語句如下:
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個關鍵參數(shù),分別是was和slowms,其中:
was=0,代表不記錄任何的語句;
was=1,代表記錄執(zhí)行時間超過slowms的語句
was=2,代表記錄所有的語句
slowms代表語句的閾值,單位是ms
上圖中的結果代表我們的實例會收集所有的查詢語句。profile收集的查詢語句結果存放在admin數(shù)據(jù)庫中的system.profile集合中,可以通過下面的方法進行訪問:
test1:PRIMARY>useadmin switchedtodbadmin 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數(shù)據(jù)庫中的system.profile是一個固定集合,保存著超過設置的慢查詢的結果。我們來看里面的一條慢查詢。
利用下面的方法,來拿到一條數(shù)據(jù),并對其中的關鍵字段進行注釋說明:
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,#掃描的索引數(shù) "docsExamined":1,#掃描的行數(shù) "cursorExhausted":true, "numYield":0, "nreturned":1,#返回的值的行數(shù) "locks":{ xxxx#鎖信息 }, "flowControl":{ }, "storage":{ }, "responseLength":647, "protocol":"op_query", "millis":0,#這個查詢的執(zhí)行時間,因為我們設置的profilestatus是0,因此所有操作都被記錄了。 "planSummary":"IDHACK",#針對_id進行查詢 "execStats":{#查詢執(zhí)行狀態(tài) "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"), "clie
03 慢查詢分析利器---explain
通常情況下,我們可以使用MongoDB的explain語法來分析一個語句的查詢性能,包含是否用到索引、掃描行數(shù)等信息,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":{ # 代表查詢的執(zhí)行計劃 "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", # 查詢的階段,很重要,下面詳細介紹 "limitAmou
首先解釋下stage的幾個階段:
- COLLSCAN---全表掃描
- IXSCAN---索引掃描
- FETCH---根據(jù)索引去檢索文檔
- SHARD_MERGE---合并分片結果
- IDHACK---針對id進行查詢
- LIMIT---執(zhí)行l(wèi)imit
了解了這些stage的階段之后,我們可以看到,一個查詢的過程是一層一層解析的,所以可以看到,stage這個字段有嵌套的情況。winningPlan中的執(zhí)行計劃也是按照一層一層的順序去執(zhí)行:
1、先執(zhí)行最內層的索引掃描(IXSCAN);
2、再執(zhí)行外面的FETCH,根據(jù)索引去拿文檔
3、執(zhí)行最后一步的limit,取指定數(shù)目個結果返回給客戶端
以上就是MongoDB profile分析慢查詢的示例的詳細內容,更多關于MongoDB profile分析慢查詢的資料請關注本站其它相關文章!
版權聲明:本站文章來源標注為YINGSOO的內容版權均為本站所有,歡迎引用、轉載,請保持原文完整并注明來源及原文鏈接。禁止復制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務器上建立鏡像,否則將依法追究法律責任。本站部分內容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學習參考,不代表本站立場,如有內容涉嫌侵權,請聯(lián)系alex-e#qq.com處理。