根據(jù)索引in查詢, 掃描索引3條 keysExamined 3, 返回文檔數(shù)1條 nReturned 1, 耗時 millis 452毫秒, execStats中executionTimeMillisEstimate都是0.
問題1: executionTimeMillisEstimate都是0. 為啥整個查詢卻消耗452毫秒.
問題2: 走了索引,只掃描索引3條,返回文檔數(shù)1條,消耗452毫秒,怎么優(yōu)化或者怎么調(diào)整它.
問題3: 在其它的執(zhí)行計劃中我看到inputStage.stage.FETCH操作耗時也很高,在200~1000毫秒.FETCH根據(jù)索引取下文檔為啥還要這么多時間呢.
求助 @Mongoing中文社區(qū) @bguo
{
"op": "query",
"ns": "webDevice",
"query": {
"find": "webDevice",
"filter": {
"lid": {
"$in": [
"40CnwyHkVmnA9kbScMLNLneaxuS4Tcj",
"140CnwyHkVmnA9kbScMLNLneaxuS4Tcj"
]
}
},
"projection": {
"$sortKey": {
"$meta": "sortKey"
}
},
"sort": {
"createTime": -1
},
"limit": 1,
"shardVersion": [
{
"$timestamp": {
"t": 106,
"i": 0
}
},
{
"$oid": "59b0039e9b5e66530435be05"
}
]
},
"keysExamined": 3,
"docsExamined": 1,
"hasSortStage": true,
"cursorExhausted": true,
"keyUpdates": 0,
"writeConflicts": 0,
"numYield": 0,
"locks": {
"Global": {
"acquireCount": {
"r": 2
}
},
"Database": {
"acquireCount": {
"r": 1
}
},
"Collection": {
"acquireCount": {
"r": 1
}
}
},
"nreturned": 1,
"responseLength": 1267,
"protocol": "op_command",
"millis": 452,
"execStats": {
"stage": "CACHED_PLAN",
"nReturned": 1,
"executionTimeMillisEstimate": 0,
"works": 2,
"advanced": 1,
"needTime": 0,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"inputStage": {
"stage": "PROJECTION",
"nReturned": 1,
"executionTimeMillisEstimate": 0,
"works": 5,
"advanced": 1,
"needTime": 4,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"transformBy": {
"$sortKey": {
"$meta": "sortKey"
}
},
"inputStage": {
"stage": "SORT",
"nReturned": 1,
"executionTimeMillisEstimate": 0,
"works": 5,
"advanced": 1,
"needTime": 4,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"sortPattern": {
"createTime": -1
},
"memUsage": 1031,
"memLimit": 33554432,
"limitAmount": 1,
"inputStage": {
"stage": "SORT_KEY_GENERATOR",
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 4,
"advanced": 0,
"needTime": 2,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"inputStage": {
"stage": "SHARDING_FILTER",
"nReturned": 1,
"executionTimeMillisEstimate": 0,
"works": 3,
"advanced": 1,
"needTime": 1,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"chunkSkips": 0,
"inputStage": {
"stage": "FETCH",
"nReturned": 1,
"executionTimeMillisEstimate": 0,
"works": 3,
"advanced": 1,
"needTime": 1,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 1,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 1,
"executionTimeMillisEstimate": 0,
"works": 3,
"advanced": 1,
"needTime": 1,
"needYield": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"lid": -1
},
"indexName": "lid_-1",
"isMultiKey": false,
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": 1,
"direction": "forward",
"indexBounds": {
"lid": [
"[\"40CnwyHkVmnA9kbScMLNLneaxuS4Tcj\", \"40CnwyHkVmnA9kbScMLNLneaxuS4Tcj\"]",
"[\"140CnwyHkVmnA9kbScMLNLneaxuS4Tcj\", \"140CnwyHkVmnA9kbScMLNLneaxuS4Tcj\"]"
]
},
"keysExamined": 3,
"dupsTested": 0,
"dupsDropped": 0,
"seenInvalidated": 0
}
}
}
}
}
}
},
"ts": {
"$date": 1514285478923
},
"client": "10.105.122.126",
"allUsers": [
{
"user": "__system",
"db": "local"
}
],
"user": "__system@local",
"_id": "c044e94198e245f3e61b39d230feb393-20171226105118923-200109374"
}
我補充一下我的環(huán)境: 機器是8核16內(nèi)存. 機器上部署有5個mongodb實例(在docker容器里面),1個mongos,1個config,3個shard(1個主,1個從,1個arbiter).
以下是docker的內(nèi)存使用情況.
| cpu使用情況 | 內(nèi)存使用情況 | |
|---|---|---|
| arbiter實例 | 1.83% | 80.18MiB / 15.51GiB |
| shard2從 | 3.09% | 5.306GiB / 15.51GiB |
| config | 1.81% | 1.449GiB / 15.51GiB |
| shard3主 | 2.56% | 5.025GiB / 15.51GiB |
| mongos | 0.37% | 188.3MiB / 15.51GiB |
其中config,shard主,shard從.3個實例都設(shè)置了CacheSizeGB為3.
目前從資源使用情況來看,CPU使用率都很低,內(nèi)存config雖然限制了3GB,但整個docker容器只用了1.5GB的內(nèi)存.
下次記得把原始查詢也發(fā)出來,我們看著更方便些。從執(zhí)行計劃來反推,查詢大約是
db.webDevice.find({
lid: {
$in: [
"40CnwyHkVmnA9kbScMLNLneaxuS4Tcj",
"140CnwyHkVmnA9kbScMLNLneaxuS4Tcj"
]
}
}).sort({createTime: -1}).limit(1);
因為命中索引,這個查詢獲取數(shù)據(jù)的速度實際上比較快,你也提到在一段時間內(nèi)第二次查詢就快了,這是一個很明顯的特點,代表內(nèi)存不足。MongoDB和其他數(shù)據(jù)庫一樣,都會使用空閑內(nèi)存緩沖索引和數(shù)據(jù),當(dāng)內(nèi)存不足時就會使用LRU算法清理舊數(shù)據(jù)換入新數(shù)據(jù)再繼續(xù)查詢。因為這個過程涉及到磁盤數(shù)據(jù)交換,速度會大大降低。發(fā)生這種情況有一個特點,就是一段時間內(nèi)第二次執(zhí)行時速度就快了(因為數(shù)據(jù)已經(jīng)在內(nèi)存中)。但是如果過一段時間再執(zhí)行,速度又會變慢(因為又被換出內(nèi)存了)。所以你的情況實際上就是受限于硬件。
既然如此最直接的解決辦法就是:
如果不能從硬件方面解決,有一點可以嘗試就是用CPU換內(nèi)存。做法是盡可能調(diào)小cacheSizeGB(是的沒錯,是調(diào)小)??臻e出來的內(nèi)存操作系統(tǒng)會用來緩沖磁盤數(shù)據(jù),而磁盤數(shù)據(jù)是經(jīng)過壓縮的,體積更小,因此可以緩沖更多數(shù)據(jù)到內(nèi)存中。但作為交換,在使用這些數(shù)據(jù)時需要經(jīng)過CPU再進行一次解壓從而額外消耗CPU。即使這樣,效果也比從磁盤讀取要好很多。整個過程是自動進行的,你需要做的只是調(diào)小cacheSizeGB。
這種做法可以在一定程度上緩解內(nèi)存不足的問題,但不是萬能的:
基于你的新的疑問,以下幾點補充:
疑問1: 按照你說的方式調(diào)小cacheSizeGB,應(yīng)該怎么調(diào)整比較合理
我在上面有提到,這樣做的效果有限,是受制于壓縮率的限制。所以多容納的數(shù)據(jù)實際就是壓縮的數(shù)據(jù)。比如1G的內(nèi)存能放多少數(shù)據(jù)?
所以調(diào)到多少,其實要看你想往內(nèi)存里放多少數(shù)據(jù),而這往往是一個不確定的數(shù)值。這里會有另外一個概念叫做工作集(working set),就是你經(jīng)常用到的那些數(shù)據(jù)。比如你的數(shù)據(jù)庫共有100GB數(shù)據(jù),但是你經(jīng)常用到的部分只有10GB,那么你的內(nèi)存只要能裝下10GB數(shù)據(jù),應(yīng)用在大部分時候就可以非???,剩下的情況忽略就好了。
基于上面這些分析,你應(yīng)該可以算一下,你的工作集有多大,數(shù)據(jù)壓縮率有多大,那么需要把cacheSizeGB調(diào)到多小才能容納下工作集(又或者調(diào)到多小都不可能容納下工作集)。你的情況是內(nèi)存不足CPU空閑,所以如果懶得算,直接把cacheSizeGB調(diào)到最小值就好了。
疑問2: config只用了1.5GB內(nèi)存(限制了CacheSizeGB3GB).可以說明索引都加載到了內(nèi)存中嗎?
這說明config數(shù)據(jù)庫(元數(shù)據(jù))的索引和數(shù)據(jù)都加載到內(nèi)存中了。注意數(shù)據(jù)的索引肯定是在shard中,與config無關(guān)。而且大頭是在shard上面。
順便提一下,如果不是實驗?zāi)康模緵]必要分這么多片。因為在一臺機器上分再多片,硬件資源也只有這么多,對于性能沒有什么意義,反而還會有額外的傳輸開銷。
疑問3: mongodb remove數(shù)據(jù)后,查詢卻越來越慢是什么情況?
remove之后跟查詢沒有本質(zhì)上的聯(lián)系,可能只是湊巧發(fā)生在一起。如果你有足夠的證據(jù)覺得這兩者確實有聯(lián)系,請另開問題描述清楚問題的上下文以及你發(fā)現(xiàn)的情況,必要的時候也可以求助于MongoDB JIRA。如果一定要做一個無根據(jù)的猜測,我覺得可能是remove時導(dǎo)致熱數(shù)據(jù)被換出內(nèi)存(注意remove也需要先找到滿足條件的數(shù)據(jù)然后才能刪除),引起后面的查詢需要重新從磁盤上加載數(shù)據(jù)造成的。
北大青鳥APTECH成立于1999年。依托北京大學(xué)優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國IT技能型緊缺人才,是大數(shù)據(jù)專業(yè)的國家
達內(nèi)教育集團成立于2002年,是一家由留學(xué)海歸創(chuàng)辦的高端職業(yè)教育培訓(xùn)機構(gòu),是中國一站式人才培養(yǎng)平臺、一站式人才輸送平臺。2014年4月3日在美國成功上市,融資1
北大課工場是北京大學(xué)校辦產(chǎn)業(yè)為響應(yīng)國家深化產(chǎn)教融合/校企合作的政策,積極推進“中國制造2025”,實現(xiàn)中華民族偉大復(fù)興的升級產(chǎn)業(yè)鏈。利用北京大學(xué)優(yōu)質(zhì)教育資源及背
博為峰,中國職業(yè)人才培訓(xùn)領(lǐng)域的先行者
曾工作于聯(lián)想擔(dān)任系統(tǒng)開發(fā)工程師,曾在博彥科技股份有限公司擔(dān)任項目經(jīng)理從事移動互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍懿科技有限責(zé)任公司從事總經(jīng)理職務(wù)負(fù)責(zé)iOS教學(xué)及管理工作。
浪潮集團項目經(jīng)理。精通Java與.NET 技術(shù), 熟練的跨平臺面向?qū)ο箝_發(fā)經(jīng)驗,技術(shù)功底深厚。 授課風(fēng)格 授課風(fēng)格清新自然、條理清晰、主次分明、重點難點突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫,具有快速界面開發(fā)的能力,對瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁制作和網(wǎng)頁游戲開發(fā)。
具有10 年的Java 企業(yè)應(yīng)用開發(fā)經(jīng)驗。曾經(jīng)歷任德國Software AG 技術(shù)顧問,美國Dachieve 系統(tǒng)架構(gòu)師,美國AngelEngineers Inc. 系統(tǒng)架構(gòu)師。