MongoDB索引與優(yōu)化詳解

在MongoDB中通過建立索引可以進行高效的查詢芍耘,如果沒有索引MongoDB將會掃描整個集合與查詢的條件進行匹配蒋纬,這對于性能會造成很大的消耗臀蛛。

技術博客: Node.js技術棧

快速導航

面試指南

  • 生產環(huán)境如何正確創(chuàng)建索引?吓笙,參考:#

Mongodb索引類型

MongoDB提供了不同的索引類型支持在不同的業(yè)務場景進行查詢

1. _id索引

絕大多數集合默認建立索引己儒,對于每個插入的數據崎岂,MongoDB都會生成一條唯一的_id字段。

例如新創(chuàng)建一個集合時

db.demo_admin2.insert({x:1})
db.demo_admin2.getIndexes() # 查看集合索引闪湾,可看到_id索引

2. 單鍵索引

是最普通的索引冲甘,單鍵索引不會自動創(chuàng)建

例如一條記錄形式為:{x:1,y:2,z:3},只要在x字段上建立索引之后途样,就可以用x為條件進行查詢

db.demo_admin2.ensureIndex({x:1}) # 創(chuàng)建索引
db.demo_admin2.find({x:1}); # 使用索引查詢

3. 多鍵索引

多鍵索引與單鍵索引區(qū)別在于多鍵索引的值具有多個記錄江醇,是一個數組

db.demo_admin2.insert({x:[1,2,3,4]})

4. 復合索引

當查詢條件為多個時,需要建立復合索引

插入記錄{'x':1,'y':2,'z':3}

db.demo_admin2.insert({'x':1,'y':2,'z':3});

創(chuàng)建索引

db.demo_3.ensureIndex({x:1,y:1}) # 1升序何暇,-1降序

使用{x:1,y:1}作為條件進行查詢

db.demo_admin2.find({x:1,y:2})

5. 過期索引

指在一段時間后會過期的索引陶夜,此索引過一段時間會過期,索引過期后裆站,相應的數據會被刪除条辟,適合存儲一些在一段時間之后會失效的數據,比如用戶登錄信息宏胯,這樣就不需要用到session了羽嫡。

5.1 創(chuàng)建過期索引

建立索引的時候需要多用一個參數,指定索引的有效時間——expireAfterSeconds肩袍,單位為秒

如下示例為time字段創(chuàng)建過期索引

db.demo_3.ensureIndex({time:1},{expireAfterSeconds:10})

5.2 過期索引限制

  • 過期索引字段值必須是指定的時間類型厂僧,必須是ISODate或ISODate數組,不能使用時間戳了牛,否則不能被自動刪除颜屠。

  • 如果指定了ISODate數組,則按照最小的時間進行刪除鹰祸。 過期索引不能是復合索引甫窟。

  • 刪除時間不是精確的,刪除過程是由后臺程序每60s跑一次蛙婴,而且刪除也需要一些時間粗井,所以存在誤差。

db.demo_3.ensureIndex({time:1},{expireAfterSeconds:30}
db.demo_3.insert({time:new Date()});

6. 全文索引

在mongodb中每個集合只允許創(chuàng)建一個索引,因此不用擔心存在多個索引造成沖突的問題浇衬。

6.1 全文索引創(chuàng)建

全文索引創(chuàng)建方法與創(chuàng)建單鍵索引懒构、復合索引類似。value換成'text'耘擂,$**匹配集合下所有

為一個字段創(chuàng)建全文索引

db.articles.ensureIndex({key:"text"})

為多個字段創(chuàng)建全文索引

db.articles.ensureIndex({key_1:"text"},{key_2:"text"})

為集合中所有的字段創(chuàng)建全文索引

db.articles.ensureIndex({"$**":"text"})

6.2 實例

建立索引

db.article.ensureIndex({"article":"text"})
db.articles.find({$text:{$search:"coffee"}})
db.articles.find({$text:{$search:"aa bb cc"}}) # 包含aa或bb或cc的數據
db.articles.find({$text:{$search:"aa bb -cc"}}) # 同時包含aa胆剧、bb且不包含cc的數據
db.articles.find({$text:{$search:"\"aa\" \"bb\" \"cc\""}})# 同時包含aa、bb醉冤、cc的數據(用""包裹起來秩霍,引號需要用反斜杠\轉義)

6.3 mongodb相似度查詢

$meta操作符:{score:{$meta:'textScore'}}

查詢結果的相似度,搜索出的結果會多出一個score字段蚁阳,這個得分越高铃绒,相關度越高。

db.article.find({$text:{$search:"aa bb ff"}},{score:{$meta:"textScore"}})

加上.sort方法可排序

db.article.find({$text:{$search:"aa bb ff"}},{score:{$meta:"textScore"}}).sort({score:{$meta:"textScore"}})

6.4 全局索引的限制

  1. 每次查詢螺捐,只能指定一個$text查詢
  2. $text查詢不能出現在$nor查詢中
  3. 查詢中如果包含了$text, hint不再起作用
  4. MongoDB全文索引還不支持中文

7.地理位置索引

  • 2d索引颠悬,用于存儲和查找平面上的點
  • 2dsphere索引,用于存儲和查找球面上的點

索引屬性

1.索引屬性name

MongoDB會自動的創(chuàng)建定血,規(guī)則是key_1 或者 key_-1 1或者-1代表排序方向椿疗,一般影響不大,長度一般有限制125字節(jié)

db.collection.ensureIndex({indexValue},{name: key})

為了見名知意我們可以自己來命名

db.demo_3.ensureIndex({x:1,y:1,z:1,n:1},{name:'xyz-name'});

刪除索引

db.demo_3.dropIndex(indexName)

2. 索引屬性unique唯一性指定

類似關系型數據庫字段的唯一約束

db.demo_3.ensureIndex({m:1,n:1},{unique:true})

索引實例測試

建立500萬條數據糠悼,分別用來測試建立索引和未建立索引的差別,只有在大量數據下才有效果浅乔,以下的示例中的時間消耗值倔喂,各電腦配置的不同在不同電腦上測試也會有不同的差別。

  • 建立測試數據
> for(var i=0; i<5000000; i++) db.demo_user.insert({id: i})
WriteResult({ "nInserted" : 1 })
  • 未建立索引情況數據查詢

在未建立索引的情況下靖苇,執(zhí)行數據查詢的時間消耗在6秒多席噩。

圖片描述
  • 建立索引情況查詢數據
db.getCollection('demo_user').ensureIndex({"id": 1}) # 建立索引

下圖為建立索引的情況,在數據查詢中僅用了0.001秒贤壁,可見建立索引的重要的性悼枢。

圖片描述

索引導致的庫級鎖

這是一個很坑爹的事情,MongoDB沒有像MySql脾拆、Oracle擁有行級粒度鎖概念馒索,在MongoDB中只有庫級粒度鎖概念,意味這當你在生產環(huán)境中不小心觸發(fā)了一個寫鎖的操作時其它的業(yè)務也會受影響名船。

MongoDB中建立索引就是一個觸發(fā)寫鎖的過程绰上,通常數據量越大建立的索引占用的寫鎖時間就會越長,MongoDB中建立索引的兩種方式渠驼。

  • 前臺創(chuàng)建(錯誤)

以下為前臺建立索引演示可以看到在執(zhí)行創(chuàng)建索引命令之后蜈块,新打開一個終端查詢另一張表一直處于等待狀態(tài),直到創(chuàng)建索引完成才返回數據。

db.getCollection('demo_user').ensureIndex({"id": 1}) # 建立索引
圖片描述
  • 后臺創(chuàng)建(推薦)
    基于后臺創(chuàng)建索引的方式在執(zhí)行創(chuàng)建索引命令之后百揭,新開一個終端查詢另一個集合中的數據可以立即得到返回爽哎。
db.getCollection('demo_user').ensureIndex({"id": 1}, {background: 1}) # 建立索引
圖片描述

作者:五月君
鏈接:https://www.imooc.com/article/285899
來源:慕課網
Github: Node.js技術棧

推薦閱讀

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市器一,隨后出現的幾起案子课锌,更是在濱河造成了極大的恐慌,老刑警劉巖盹舞,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件产镐,死亡現場離奇詭異,居然都是意外死亡踢步,警方通過查閱死者的電腦和手機癣亚,發(fā)現死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來获印,“玉大人述雾,你說我怎么就攤上這事〖娣幔” “怎么了玻孟?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鳍征。 經常有香客問我黍翎,道長,這世上最難降的妖魔是什么艳丛? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任匣掸,我火速辦了婚禮,結果婚禮上氮双,老公的妹妹穿的比我還像新娘碰酝。我一直安慰自己,他們只是感情好戴差,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布送爸。 她就那樣靜靜地躺著,像睡著了一般暖释。 火紅的嫁衣襯著肌膚如雪袭厂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天球匕,我揣著相機與錄音嵌器,去河邊找鬼。 笑死谐丢,一個胖子當著我的面吹牛爽航,可吹牛的內容都是我干的蚓让。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼讥珍,長吁一口氣:“原來是場噩夢啊……” “哼历极!你這毒婦竟也來了?” 一聲冷哼從身側響起衷佃,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤趟卸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后氏义,有當地人在樹林里發(fā)現了一具尸體锄列,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年惯悠,在試婚紗的時候發(fā)現自己被綠了邻邮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡克婶,死狀恐怖筒严,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情情萤,我是刑警寧澤鸭蛙,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站筋岛,受9級特大地震影響娶视,放射性物質發(fā)生泄漏。R本人自食惡果不足惜睁宰,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一肪获、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧勋陪,春花似錦、人聲如沸硫兰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽劫映。三九已至违孝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泳赋,已是汗流浹背雌桑。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留祖今,地道東北人校坑。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓拣技,卻偏偏與公主長得像,于是被迫代替她去往敵國和親耍目。 傳聞我的和親對象是個殘疾皇子膏斤,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內容