MongoDB的索引
1、簡介
它就像是一本書的目錄,如果沒有它,我們就需要對整個(gè)書籍進(jìn)行查找來獲取需要的結(jié)果,即所說的全盤掃描;
而有了目錄(索引)之后就可以通過它幫我們定位到目標(biāo)所在的位置,快速的獲取我們想要的結(jié)果。
2、演示
第一步,向用戶集合users中插入100W條數(shù)據(jù)
var insertUsers = function() {
var start = new Date().getTime();
for (var i = 1; i <= 1000000; i++) {
db.users.insert({
"userid": i,
"username": "wjg" + i,
"age": Math.floor(Math.random() * 100), //年齡為0~99的隨機(jī)整數(shù)
"createdate": new Date()
})
}
var end = new Date().getTime();
print("插入100W條數(shù)據(jù)共耗時(shí)" + (end - start) / 1000 + "秒");
}
LZ的渣渣I3和4G內(nèi)存總共耗時(shí)了484.623秒,約8分多鐘。任務(wù)管理器里邊可以很清楚的看到當(dāng)時(shí)CPU、內(nèi)存和磁盤使用率都普遍的增高。

第二步:查詢用戶名為“wjg465413”的文檔對象
db.users.find({username:"wjg465413"}).explain("allPlansExecution")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.users",
"indexFilterSet" : false,
"parsedQuery" : {
"username" : {
"$eq" : "wjg465413"
}
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"username" : {
"$eq" : "wjg465413"
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 865,
"totalKeysExamined" : 0,
"totalDocsExamined" : 1000000,
"executionStages" : {
"stage" : "COLLSCAN",
"filter" : {
"username" : {
"$eq" : "wjg465413"
}
},
"nReturned" : 1,
"executionTimeMillisEstimate" : 770,
"works" : 1000002,
"advanced" : 1,
"needTime" : 1000000,
"needFetch" : 0,
"saveState" : 7813,
"restoreState" : 7813,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 1000000
},
"allPlansExecution" : [ ]
},
"serverInfo" : {
"host" : "Jack",
"port" : 27017,
"version" : "3.0.3",
"gitVersion" : "b40106b36eecd1b4407eb1ad1af6bc60593c6105"
},
"ok" : 1
}
說明:這里的explain方法相當(dāng)于查詢計(jì)劃,它會(huì)返回給你查詢過程的詳細(xì)信息。它的參數(shù)有三種模式:“queryPlanner”(查詢計(jì)劃[默認(rèn)])、“executionStats”(執(zhí)行狀態(tài))和“allPlansExecution”(所有執(zhí)行計(jì)劃),這里我們只關(guān)注它返回給我們的以下幾個(gè)信息。
"executionTimeMillis" : 865 //執(zhí)行的毫秒數(shù) 注:如果你是第一次執(zhí)行,可能會(huì)花費(fèi)更長的時(shí)間 "totalDocsExamined" : 1000000 //共檢查的文檔數(shù)
第三步:在用戶名“username”字段上加上索引
db.users.createIndex({ "username" : 1 })
重新執(zhí)行上次的查詢操作
db.users.find({username:"wjg465413"}).explain("allPlansExecution")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.users",
"indexFilterSet" : false,
"parsedQuery" : {
"username" : {
"$eq" : "wjg465413"
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"username" : 1
},
"indexName" : "username_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"username" : [
"[\"wjg465413\", \"wjg465413\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 53,
"totalKeysExamined" : 1,
"totalDocsExamined" : 1,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needFetch" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needFetch" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"username" : 1
},
"indexName" : "username_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"username" : [
"[\"wjg465413\", \"wjg465413\"]"
]
},
"keysExamined" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0,
"matchTested" : 0
}
},
"allPlansExecution" : [ ]
},
"serverInfo" : {
"host" : "Jack",
"port" : 27017,
"version" : "3.0.3",
"gitVersion" : "b40106b36eecd1b4407eb1ad1af6bc60593c6105"
},
"ok" : 1
}
可以看到兩次的查詢計(jì)劃有很大的差別,我們還是著重看下那兩個(gè)屬性值。
"executionTimeMillis" : 53 //執(zhí)行的毫秒數(shù) "totalDocsExamined" : 1 //共檢查的文檔數(shù)
加過索引之后查詢這個(gè)文檔所耗費(fèi)的時(shí)間僅僅為53毫秒,并且掃描一次直接定位,性能提升了16倍??梢姾侠硎褂盟饕闹匾?!
注:“_id”字段是Mongo為我們默認(rèn)添加的索引,而且是唯一索引,保證了數(shù)據(jù)的唯一性,不可以移除。另外,使用limit(1)限制查詢結(jié)果的數(shù)量也可以提高查詢速度
3、索引的類型
a)、單一索引:可以在數(shù)據(jù)集上任意一個(gè)字段上建立索引,包括普通的屬性鍵、內(nèi)嵌文檔以及內(nèi)嵌文檔中的屬性鍵。
db.users.createIndex({ "username" : 1 }) //普通屬性鍵的索引
//假設(shè)class是一個(gè)內(nèi)嵌的文檔
db.users.createIndex({ "class" : 1 }) //內(nèi)嵌文檔的索引
db.users.createIndex({ "class.classname" : 1 }) //內(nèi)嵌文檔中的屬性鍵索引
索引方向:1表示升序,-1表示降序
b)、復(fù)合索引:以多個(gè)屬性鍵為基礎(chǔ)而建立得索引
db.users.createIndex({ "username" : 1, "age" : -1, "userid" : 1 }) //在“username”、“age”和“userid”上建立復(fù)合索引
索引前綴:通過建立上邊的復(fù)合索引之后,Mongo就相當(dāng)于同時(shí)擁有了三個(gè)索引一樣,分別是{"username" : 1},{"username" : 1, "age" : -1}和{"username" : 1, "age" : -1, "userid" : 1},但是像{"age" : -1},{"userid" : 1}或者{"age" : -1, "userid" : 1}這三個(gè)索引并不會(huì)起作用。所以它會(huì)使用包含了前綴(首個(gè))的索引的作為復(fù)合索引
c)、多鍵索引:為數(shù)組中的多個(gè)值建立索引以實(shí)現(xiàn)高效查詢。
注:Ⅰ、不允許在多個(gè)數(shù)組上建立復(fù)合索引
Ⅱ、不能指定片鍵作為多鍵索引
?、?、哈希索引不能是多鍵
Ⅳ、多鍵索引不支持覆蓋查詢
d)、地理空間索引和查詢:Mongo提供了兩種曲面類型的索引:2dsphere索引和2d索引。查詢類型包括:包含(inclusion),交叉(intersection)和接近(proximity)
e)、文本索引:用來支持查詢包含了字符串或者字符串?dāng)?shù)組的文檔
db.users.createIndex({"username" : "text"})
注:文本索引不支持排序并且一個(gè)復(fù)合文本索引不能再包含其他任何索引了
f)、哈希索引:它可以在使用了哈希片鍵進(jìn)行分片的數(shù)據(jù)集上進(jìn)行索引,支持相等查詢,但是不支持范圍查詢
db.users.createIndex({"username" : "hashed"})
4、索引特性
a)、TTL(Time-To-Live)索引:是一種具有生命周期的索引,它允許為每一個(gè)文檔設(shè)置一個(gè)超時(shí)時(shí)間
db.users.createIndex({ "createdate" : 1 },{ "expireAfterSecs" : 60*60*24 })
說明:在“createdate”字段上建立一個(gè)TTL索引,當(dāng)這個(gè)自段存在并且是日期類型,當(dāng)服務(wù)器時(shí)間比“createdate”字段的時(shí)間晚60*60*24秒,即24小時(shí)時(shí),文檔就會(huì)被刪除
b)、唯一索引:確保集合的每一個(gè)文檔的指定鍵都有唯一值
db.users.createIndex({"username" : 1}, {"unique" : true})
c)、稀疏索引:Mongo里邊的null會(huì)被看做值,如果有一個(gè)可能存在也可能不存在的字段,我們可以使用稀疏索引
db.users.createIndex({"age" : 1},{"sparse" : true})
4、索引操作
a)、查看所有索引
db.users.getIndexes()
b)、移除索引
db.users.dropIndex({"createdate1" : 1 })
c)、移除所有索引
db.users.dropIndexes()
d)、重建索引
db.users.reIndex()
說明:該操作會(huì)先刪除所有索引,包括“_id”,然后重新創(chuàng)建所有索引
相關(guān)文章
MongoDB系列教程(四):設(shè)置用戶訪問權(quán)限
這篇文章主要介紹了MongoDB系列教程(四):設(shè)置用戶訪問權(quán)限,本文講解了在Windows環(huán)境下如何創(chuàng)建用戶認(rèn)證,需要的朋友可以參考下2015-05-05
windows安裝mongodb6.x并設(shè)置用戶名密碼的詳細(xì)過程
這篇文章主要介紹了windows安裝mongodb6.x并設(shè)置用戶名密碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04
Mongodb億級(jí)數(shù)據(jù)性能測試和壓測
MongoDB是一個(gè)開源的、基于分布式文件存儲(chǔ)的NoSQL數(shù)據(jù)庫系統(tǒng),它使用文檔存儲(chǔ)方式,數(shù)據(jù)結(jié)構(gòu)由鍵值(key-value)對組成,本文給大家介紹了Mongodb億級(jí)數(shù)據(jù)性能測試和壓測,需要的朋友可以參考下2024-06-06
MongoDB系列教程(五):mongo語法和mysql語法對比學(xué)習(xí)
這篇文章主要介紹了MongoDB系列教程(五):mongo語法和mysql語法對比學(xué)習(xí),本文對熟悉Mysql數(shù)據(jù)庫的同學(xué)來說幫助很大,用對比的方式可以快速學(xué)習(xí)到MongoDB的命令,需要的朋友可以參考下2015-05-05
MongoDB學(xué)習(xí)之Text Search文本搜索功能
這篇文章主要給大家介紹了MongoDB之Text Search文本搜索功能的相關(guān)資料,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),對大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-05-05
MongoDB中javascript腳本編程簡介和入門實(shí)例
作為一個(gè)數(shù)據(jù)庫,MongoDB有一個(gè)很大的優(yōu)勢——它使用js管理數(shù)據(jù)庫,所以也能夠使用js腳本進(jìn)行復(fù)雜的管理——這種方法非常靈活2014-04-04
關(guān)于MongoDB數(shù)據(jù)庫學(xué)習(xí)路線指南
這篇文章主要介紹了關(guān)于MongoDB數(shù)據(jù)庫學(xué)習(xí)路線指南,給大家以學(xué)習(xí)路線地圖的形式講解該怎么學(xué)習(xí)MongoDB數(shù)據(jù)庫,需要的朋友可以參考下2023-04-04
MongoDB連接數(shù)據(jù)庫并創(chuàng)建數(shù)據(jù)等使用方法
MongoDB?是一個(gè)介于關(guān)系數(shù)據(jù)庫和非關(guān)系數(shù)據(jù)庫之間的產(chǎn)品,是非關(guān)系數(shù)據(jù)庫當(dāng)中功能最豐富,最像關(guān)系數(shù)據(jù)庫的。接下來通過本文給大家介紹MongoDB連接數(shù)據(jù)庫并創(chuàng)建數(shù)據(jù)等使用方法,感興趣的朋友一起看看吧2021-11-11

