MongoDB使用profile分析慢查詢(xún)的步驟
在MongoDB中,如果發(fā)生了慢查詢(xún),我們?nèi)绾蔚玫竭@些慢查詢(xún)的語(yǔ)句,并優(yōu)化呢?今天來(lái)看這塊兒的一些心得。
01 如何收集慢查詢(xún)?
在MongoDB中,通??梢蚤_(kāi)啟profile來(lái)收集慢日志,查看當(dāng)前profile狀態(tài)的語(yǔ)句如下:
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個(gè)關(guān)鍵參數(shù),分別是was和slowms,其中:
was=0,代表不記錄任何的語(yǔ)句;
was=1,代表記錄執(zhí)行時(shí)間超過(guò)slowms的語(yǔ)句
was=2,代表記錄所有的語(yǔ)句
slowms代表語(yǔ)句的閾值,單位是ms
上圖中的結(jié)果代表我們的實(shí)例會(huì)收集所有的查詢(xún)語(yǔ)句。profile收集的查詢(xún)語(yǔ)句結(jié)果存放在admin數(shù)據(jù)庫(kù)中的system.profile集合中,可以通過(guò)下面的方法進(jìn)行訪問(wèn):
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慢查詢(xún)集合分析
admin數(shù)據(jù)庫(kù)中的system.profile是一個(gè)固定集合,保存著超過(guò)設(shè)置的慢查詢(xún)的結(jié)果。我們來(lái)看里面的一條慢查詢(xún)。
利用下面的方法,來(lái)拿到一條數(shù)據(jù),并對(duì)其中的關(guān)鍵字段進(jìn)行注釋說(shuō)明:
test1:PRIMARY> db.system.profile.findOne({'op':'query'}) { "op" : "query", # 操作類(lèi)型 "ns" : "admin.system.users", # 命名空間 "command" : { "find" : "system.users", "filter" : { "_id" : "admin.root" # 過(guò)濾的字段 }, "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, # 這個(gè)查詢(xún)的執(zhí)行時(shí)間,因?yàn)槲覀冊(cè)O(shè)置的profilestatus是0,因此所有操作都被記錄了。 "planSummary" : "IDHACK", # 針對(duì)_id進(jìn)行查詢(xún) "execStats" : { # 查詢(xún)執(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"), "client" : "xx.xx.xx.xx", # 查詢(xún)的客戶(hù)端IP地址 "allUsers" : [ # 所有的用戶(hù)信息 { "user" : "root", "db" : "admin" } ], "user" : "root@admin" # 使用的用戶(hù)信息 }
03 慢查詢(xún)分析利器---explain
通常情況下,我們可以使用MongoDB的explain語(yǔ)法來(lái)分析一個(gè)語(yǔ)句的查詢(xún)性能,包含是否用到索引、掃描行數(shù)等信息,explain語(yǔ)法的基本用法:
后置寫(xiě)法 db.system.profile.find({'op':'query'}).explain() 前置寫(xiě)法 db.system.profile.explain().find({'op':'query'})
其中,explain可以放在查詢(xún)語(yǔ)句的后面或者前面,當(dāng)然find語(yǔ)法也可以是update、remove、insert
explain語(yǔ)法的輸出分為3種不同的詳細(xì)程度,分別如下:
三種清晰度模式,清晰度越高,則輸出的信息越全,默認(rèn)情況下是queryPlanner:
1、queryPlanner模式(默認(rèn))
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模式輸出的信息最多。
下面是一個(gè)explain語(yǔ)法的輸出內(nèi)容,查詢(xún)的SQL如下:
db.getCollection('files').find( {"cTime":{ "$gte":ISODate("2021-04-18"), "$lt":ISODate("2021-04-19") }}).limit(1000).explain("allPlansExecution")
輸出的結(jié)果如下:
{ "queryPlanner" : { # 代表查詢(xún)的執(zhí)行計(jì)劃 "plannerVersion" : 1, # 版本號(hào) "namespace" : "fs.files", # 查詢(xún)的命名空間,也就是集合名稱(chēng) "indexFilterSet" : false, # 是否使用了索引過(guò)濾,注意,它并不能判定是否使用了索引 "parsedQuery" : { # 查詢(xún)語(yǔ)法解析樹(shù) "$and" : [ { "cTime" : { "$lt" : ISODate("2021-04-19T00:00:00Z") } }, { "cTime" : { "$gte" : ISODate("2021-04-18T00:00:00Z") } } ] }, "winningPlan" : { # 最終選擇的查詢(xún)計(jì)劃 "stage" : "LIMIT", # 查詢(xún)的階段,很重要,下面詳細(xì)介紹 "limitAmount" : 1000, # 查詢(xún)結(jié)果的limit值 "inputStage" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", # 代表索引掃描 "keyPattern" : { "cTime" : 1 }, "indexName" : "cTime_1", # 索引名稱(chēng) "isMultiKey" : false, # 下面4個(gè)字段都是索引類(lèi)型分析 "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 1, "direction" : "forward", "indexBounds" : { "cTime" : [ "[new Date(1618704000000), new Date(1618790400000))" ] } } } }, "rejectedPlans" : [ ] # 候選的沒(méi)被選中的查詢(xún)計(jì)劃 }, "serverInfo" : { "host" : "xxxx", "port" : 24999, "version" : "3.2.8", "gitVersion" : "ed70e33130c977bda0024c125b56d159573dbaf0" }, "ok" : 1 }
首先解釋下stage的幾個(gè)階段:
- COLLSCAN---全表掃描
- IXSCAN---索引掃描
- FETCH---根據(jù)索引去檢索文檔
- SHARD_MERGE---合并分片結(jié)果
- IDHACK---針對(duì)id進(jìn)行查詢(xún)
- LIMIT---執(zhí)行l(wèi)imit
了解了這些stage的階段之后,我們可以看到,一個(gè)查詢(xún)的過(guò)程是一層一層解析的,所以可以看到,stage這個(gè)字段有嵌套的情況。winningPlan中的執(zhí)行計(jì)劃也是按照一層一層的順序去執(zhí)行:
1、先執(zhí)行最內(nèi)層的索引掃描(IXSCAN);
2、再執(zhí)行外面的FETCH,根據(jù)索引去拿文檔
3、執(zhí)行最后一步的limit,取指定數(shù)目個(gè)結(jié)果返回給客戶(hù)端
以上就是MongoDB profile分析慢查詢(xún)的示例的詳細(xì)內(nèi)容,更多關(guān)于MongoDB profile分析慢查詢(xún)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
MongoDB的$sample、aggregate和$rand實(shí)現(xiàn)隨機(jī)選取數(shù)據(jù)
在MongoDB中,我們可以使用內(nèi)置的$sample聚合操作符來(lái)隨機(jī)生成數(shù)據(jù),$sample可以從集合文檔中隨機(jī)選擇指定數(shù)量的文檔,但由于其查詢(xún)整個(gè)集合的性能問(wèn)題,應(yīng)該慎用,aggregate方法以及$rand函數(shù)的結(jié)合使用可以實(shí)現(xiàn)更加靈活的查詢(xún)操作,并且可以對(duì)查詢(xún)結(jié)果進(jìn)行精細(xì)篩選2024-01-01MongoDB 中聚合統(tǒng)計(jì)計(jì)算--$SUM表達(dá)式
這篇文章主要介紹了MongoDB 中聚合統(tǒng)計(jì)計(jì)算--$SUM表達(dá)式的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08MongoDB如何正確中斷正在創(chuàng)建的索引詳解
這篇文章主要給大家介紹了關(guān)于MongoDB如何正確中斷正在創(chuàng)建的索引的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12deepin 15.3 X64系統(tǒng)中安裝mongodb的方法步驟
這篇文章主要跟大家分享了deepin 15.3 X64系統(tǒng)中安裝mongodb的方法步驟,文中將安裝步驟介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)跟著小編一起學(xué)習(xí)學(xué)習(xí)吧。2017-04-04關(guān)于單臺(tái)MongoDB實(shí)例開(kāi)啟Oplog的過(guò)程詳解
這篇文章主要給大家介紹了關(guān)于單臺(tái)MongoDB實(shí)例開(kāi)啟Oplog的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09mongodb增刪改查詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了mongodb增刪改查詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08express使用Mongoose連接MongoDB操作示例【附源碼下載】
這篇文章主要介紹了express使用Mongoose連接MongoDB操作,結(jié)合實(shí)例形式分析了express使用Mongoose連接MongoDB的具體步驟與相關(guān)實(shí)現(xiàn)技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2019-07-07MongoDB導(dǎo)出查詢(xún)結(jié)果到文件例子
這篇文章主要介紹了MongoDB導(dǎo)出查詢(xún)結(jié)果到文件例子,本文直接給出示例代碼,簡(jiǎn)潔易懂,需要的朋友可以參考下2015-02-02