Mongodb高級篇-性能優(yōu)化

1篮条、監(jiān)控

mongodb可以通過profile來監(jiān)控?cái)?shù)據(jù)堰怨,進(jìn)行優(yōu)化帝洪。

查看當(dāng)前是否開啟profile功能用命令:db.getProfilingLevel()返回level等級探孝,值為0|1|2审丘,分別代表意思:0代表關(guān)閉,1代表記錄慢命令疯暑,2代表全部训柴。

開始profile功能為db.setProfilingLevel(level);

level為1的時(shí)候,慢命令默認(rèn)值為100ms妇拯,更改為db.setProfilingLevel(level,slowms)如db.setProfilingLevel(1,50)這樣就更改為50毫秒

通過db.system.profile.find() 查看當(dāng)前的監(jiān)控日志幻馁。

通過執(zhí)行db.system.profile.find({millis:{$gt:500}})能夠返回查詢時(shí)間在500毫秒以上的查詢命令。

這里值的含義是

ts:命令執(zhí)行時(shí)間
info:命令的內(nèi)容
query:代表查詢
order.order: 代表查詢的庫與集合
reslen:返回的結(jié)果集大小越锈,byte數(shù)
nscanned:掃描記錄數(shù)量
nquery:后面是查詢條件
nreturned:返回記錄數(shù)及用時(shí)
millis:所花時(shí)間

如果發(fā)現(xiàn)時(shí)間比較長仗嗦,那么就需要作優(yōu)化。

比如nscanned數(shù)很大甘凭,或者接近記錄總數(shù)稀拐,那么可能沒有用到索引查詢。

reslen很大丹弱,有可能返回沒必要的字段德撬。

nreturned很大,那么有可能查詢的時(shí)候沒有加限制躲胳。

mongo可以通過db.serverStatus()查看mongod的運(yùn)行狀態(tài)

2蜓洪、索引

如果發(fā)現(xiàn)查詢時(shí)間相對長,那么就需要做優(yōu)化坯苹。首選就是為待查詢的字段建立索引隆檀,不過需要特別注意的是,索引不是萬能靈藥粹湃。如果需要查詢超過一半的集合數(shù)據(jù)恐仑,索引還不如直接遍歷來的好。

索引的原理是通過建立指定字段的B樹再芋,通過搜索B樹來查找對應(yīng)document的地址菊霜。這也就解釋了如果需要查詢超過一半的集合數(shù)據(jù)坚冀,直接遍歷省去了搜索B樹的過程济赎,效率反而會高。

關(guān)于索引,索引列顆粒越小越好司训,什么叫顆粒越小越好构捡?在索引列中每個(gè)數(shù)據(jù)的重復(fù)數(shù)量稱為顆粒,也叫作索引的基數(shù)壳猜。如果數(shù)據(jù)的顆粒過大勾徽,索引就無法發(fā)揮該有的性能。例如统扳,我們擁有一個(gè)"age"列索引喘帚,如果在"age"列中,20歲占了50%咒钟,如果現(xiàn)在要查詢一個(gè)20歲吹由,名叫"Tom"的人,我們則需要在表的50%的數(shù)據(jù)中查詢朱嘴,索引的作用大大降低倾鲫。所以,我們在建立索引時(shí)要盡量將數(shù)據(jù)顆粒小的列放在索引左側(cè)萍嬉,以保證索引發(fā)揮最大的作用乌昔。

3、exlpain查詢執(zhí)行情況

執(zhí)行命令:

> db.order.find({ "status": 1.0, "user.uid": { $gt: 2663199.0 } }).explain()
{
    "cursor" : "BasicCursor",#游標(biāo)類型
    "nscanned" : 2010000,#掃描數(shù)量
    "nscannedObjects" : 2010000,#掃描對象
    "n" : 337800,#返回?cái)?shù)據(jù)
    "millis" : 2838,#耗時(shí)
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {#使用索引(這里沒有)
        
    }
}

通過這些信息就能判斷查詢時(shí)如何執(zhí)行的了

4壤追、數(shù)據(jù)庫設(shè)計(jì)優(yōu)化

在項(xiàng)目設(shè)計(jì)階段磕道,明確集合的用途是對性能調(diào)優(yōu)非常重要的一步。

從性能優(yōu)化的角度來看行冰,集合的設(shè)計(jì)我們需要考慮的是集合中數(shù)據(jù)的常用操作捅厂,例如我們需要設(shè)計(jì)一個(gè)日志(log)集合,日志的查看頻率不高资柔,但寫入頻率卻很高焙贷,那么我們就可以得到這個(gè)集合中常用的操作是更新(增刪改)。如果我們要保存的是城市列表呢贿堰?顯而易見辙芍,這個(gè)集合是一個(gè)查看頻率很高,但寫入頻率很低的集合羹与,那么常用的操作就是查詢故硅。

對于頻繁更新和頻繁查詢的集合,我們最需要關(guān)注的重點(diǎn)是他們的范式化程度纵搁,假設(shè)現(xiàn)在我們需要存儲一篇圖書及其作者吃衅,在MongoDB中的關(guān)聯(lián)就可以體現(xiàn)為以下幾種形式:

1.完全分離(范式化設(shè)計(jì))

示例1:

View Code
{
     "_id" : ObjectId("5124b5d86041c7dca81917"),
     "title" : "如何使用MongoDB", 
      "author" : [ 
               ObjectId("144b5d83041c7dca84416"),
              ObjectId("144b5d83041c7dca84418"),
              ObjectId("144b5d83041c7dca84420"),
     ]
 } 

我們將作者(comment) 的id數(shù)組作為一個(gè)字段添加到了圖書中去。這樣的設(shè)計(jì)方式是在非關(guān)系型數(shù)據(jù)庫中常用的腾誉,也就是我們所說的范式化設(shè)計(jì)徘层。在MongoDB中我們將與主鍵沒有直接關(guān)系的圖書單獨(dú)提取到另一個(gè)集合峻呕,用存儲主鍵的方式進(jìn)行關(guān)聯(lián)查詢。當(dāng)我們要查詢文章和評論時(shí)需要先查詢到所需的文章趣效,再從文章中獲取評論id瘦癌,最后用獲得的完整的文章及其評論。在這種情況下查詢性能顯然是不理想的跷敬。但當(dāng)某位作者的信息需要修改時(shí)讯私,范式化的維護(hù)優(yōu)勢就凸顯出來了,我們無需考慮此作者關(guān)聯(lián)的圖書西傀,直接進(jìn)行修改此作者的字段即可斤寇。

2.完全內(nèi)嵌(反范式化設(shè)計(jì))

示例2:

View Code
{
       "_id" : ObjectId("5124b5d86041c7dca81917"),
       "title" : "如何使用MongoDB",
       "author" : [
                {
                         "name" : "丁磊"
                         "age" : 40,
                         "nationality" : "china",
                },
                {
                         "name" : "馬云"
                         "age" : 49,
                         "nationality" : "china",
                },
                {
                         "name" : "張召忠"
                         "age" : 59,
                         "nationality" : "china",
                },
      ]
  }

在這個(gè)示例中我們將作者的字段完全嵌入到了圖書中去,在查詢的時(shí)候直接查詢圖書即可獲得所對應(yīng)作者的全部信息拥褂,但因一個(gè)作者可能有多本著作抡驼,當(dāng)修改某位作者的信息時(shí)時(shí),我們需要遍歷所有圖書以找到該作者肿仑,將其修改致盟。

3.部分內(nèi)嵌(折中方案)

示例3:

View Code
{
       "_id" : ObjectId("5124b5d86041c7dca81917"),
       "title" : "如何使用MongoDB",
       "author" : [ 
               {
                         "_id" : ObjectId("144b5d83041c7dca84416"),
                         "name" : "丁磊"
                },
                {
                         "_id" : ObjectId("144b5d83041c7dca84418"),
                         "name" : "馬云"
                },
                {
                         "_id" : ObjectId("144b5d83041c7dca84420"),
                         "name" : "張召忠"
                },
      ]
  }

這次我們將作者字段中的最常用的一部分提取出來。當(dāng)我們只需要獲得圖書和作者名時(shí)尤慰,無需再次進(jìn)入作者集合進(jìn)行查詢馏锡,僅在圖書集合查詢即可獲得。

這種方式是一種相對折中的方式伟端,既保證了查詢效率杯道,也保證的更新效率。但這樣的方式顯然要比前兩種較難以掌握责蝠,難點(diǎn)在于需要與實(shí)際業(yè)務(wù)進(jìn)行結(jié)合來尋找合適的提取字段党巾。如同示例3所述,名字顯然不是一個(gè)經(jīng)常修改的字段霜医,這樣的字段如果提取出來是沒問題的齿拂,但如果提取出來的字段是一個(gè)經(jīng)常修改的字段(比如age)的話,我們依舊在更新這個(gè)字段時(shí)需要大范圍的尋找并依此進(jìn)行更新肴敛。

在上面三個(gè)示例中署海,第一個(gè)示例的更新效率是最高的,但查詢效率是最低的医男,而第二個(gè)示例的查詢效率最高砸狞,但更新效率最低。所以在實(shí)際的工作中我們需要根據(jù)自己實(shí)際的需要來設(shè)計(jì)表中的字段镀梭,以獲得最高的效率刀森。

5、其他方法

熱數(shù)據(jù)法

可能你的數(shù)據(jù)集非常大报账,但是這并不那么重要研底,重要的是你的熱數(shù)據(jù)集有多大埠偿,你經(jīng)常訪問的數(shù)據(jù)有多大(包括經(jīng)常訪問的數(shù)據(jù)和所有索引數(shù)據(jù))。使用MongoDB飘哨,你最好保證你的熱數(shù)據(jù)在你機(jī)器的內(nèi)存大小之下,保證內(nèi)存能容納所有熱數(shù)據(jù)琐凭。

文件系統(tǒng)法

MongoDB的數(shù)據(jù)文件是采用的預(yù)分配模式芽隆,并且在Replication里面,Master和Replica Sets的非Arbiter節(jié)點(diǎn)都是會預(yù)先創(chuàng)建足夠的空文件用以存儲操作日志统屈。這些文件分配操作在一些文件系統(tǒng)上可能會非常慢胚吁,導(dǎo)致進(jìn)程被Block。所以我們應(yīng)該選擇那些空間分配快速的文件系統(tǒng)愁憔。這里的結(jié)論是盡量不要用ext3腕扶,用ext4或者xfs。

硬件法

這里的選擇包括了對磁盤RAID的選擇吨掌,也包括了磁盤與SSD的對比選擇半抱。

其他

如果數(shù)據(jù)文件大于系統(tǒng)內(nèi)存,查詢速度會下降幾個(gè)數(shù)量級膜宋,因?yàn)閙ongodb是內(nèi)存數(shù)據(jù)庫窿侈。我以前測試過,1000萬數(shù)據(jù)的時(shí)候沒有索引情況下查詢可能會幾秒鐘甚至更久秋茫。

這種情況史简,你最好給經(jīng)常查詢的項(xiàng)創(chuàng)建索引,有索引以后查詢速度會非常非常非常的快肛著。

另外一點(diǎn)是數(shù)據(jù)索引如果大于內(nèi)存圆兵,速度也會下降很多。而且對于多條件查詢枢贿,如果你查詢的順學(xué)和索引順序不同殉农,也不能使用索引。這個(gè)要慢慢摸索

如果你使用了replica set局荚,這個(gè)會影響寫入速度的统抬,三個(gè)replica set,速度會降低到三分之一危队。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末聪建,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子茫陆,更是在濱河造成了極大的恐慌金麸,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件簿盅,死亡現(xiàn)場離奇詭異挥下,居然都是意外死亡揍魂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門棚瘟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來现斋,“玉大人,你說我怎么就攤上這事偎蘸∽#” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵迷雪,是天一觀的道長限书。 經(jīng)常有香客問我,道長章咧,這世上最難降的妖魔是什么倦西? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮赁严,結(jié)果婚禮上扰柠,老公的妹妹穿的比我還像新娘。我一直安慰自己疼约,他們只是感情好耻矮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著忆谓,像睡著了一般裆装。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上倡缠,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天哨免,我揣著相機(jī)與錄音,去河邊找鬼昙沦。 笑死琢唾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盾饮。 我是一名探鬼主播采桃,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丘损!你這毒婦竟也來了普办?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤徘钥,失蹤者是張志新(化名)和其女友劉穎衔蹲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呈础,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舆驶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年橱健,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沙廉。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拘荡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出撬陵,到底是詐尸還是另有隱情珊皿,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布袱结,位于F島的核電站亮隙,受9級特大地震影響途凫,放射性物質(zhì)發(fā)生泄漏垢夹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一维费、第九天 我趴在偏房一處隱蔽的房頂上張望果元。 院中可真熱鬧,春花似錦犀盟、人聲如沸而晒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽倡怎。三九已至,卻和暖如春贱枣,著一層夾襖步出監(jiān)牢的瞬間监署,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工纽哥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钠乏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓春塌,卻偏偏與公主長得像晓避,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子只壳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容