索引是數(shù)據(jù)庫(kù)中的一個(gè)重要對(duì)象昧廷,主要用于支持高效查詢操作。如果沒有索引葵擎,數(shù)據(jù)庫(kù)就只能進(jìn)行全表掃描谅阿,效率將極為低下。mongodb的索引體系比較龐大酬滤,按照索引類型签餐,我準(zhǔn)備分這么幾個(gè)部分來進(jìn)行闡述:
基本索引
Text索引
GEO索引
概述
本文將簡(jiǎn)單介紹常用的基本索引類型,已經(jīng)索引的相關(guān)操作盯串。根據(jù)官方的文檔氯檐,Mongodb有這么幾種常見索引:
Default _id 主鍵索引,默認(rèn)作用在
_id
上Single Field 單鍵索引体捏,針對(duì)單個(gè)field的索引
Compound 復(fù)合索引冠摄,針對(duì)多個(gè)field的索引
Multikey Index,這個(gè)我都不知道怎么翻几缭,多鍵索引吧河泳,其實(shí)就是針對(duì)數(shù)組子項(xiàng)的索引,因?yàn)閿?shù)組有多個(gè)元素年栓,每個(gè)元素都可能的key,如果有一個(gè)索引A作用在這個(gè)key上拆挥,這就是所謂的Multikey index
Geospatial Index 針對(duì)地理位置信息的索引
Text Index 支持全文搜索的索引,2.4才支持
Hashed Index 某抓, To support hash based sharding, MongoDB provides a hashed index (page 22) type, which indexes the hash of the value of a field.
同時(shí)纸兔,mongodb提供了兩個(gè)索引的屬性:
Unique 唯一性,保證索引作用的field上的value是唯一的否副。
Sparse 稀疏性汉矿,如果一個(gè)Collection中的某個(gè)field A 只存在于某些Document上,而 A 上同時(shí)建立了索引备禀,那么用Sparse則會(huì)使查詢操作直接忽略這些記錄洲拇。
好了,概念說了很多曲尸,來講一下索引的具體操作吧呻待。創(chuàng)建一個(gè)索引很簡(jiǎn)單,看看下面這些代碼:
// 單鍵索引
db.Student.ensureIndex({code:1});
// 復(fù)合索引
db.Student.ensureIndex({name:1,time:-1})
// Multikey Index
db.Student.ensureIndex({faver.id:1});
// 唯一索引
db.Student.ensureIndex({code:1},{unique:1});
// 唯一索引同時(shí)刪除重復(fù)值
db.Student.ensureIndex({code:1},{unique:1,dropDups:1});
// 唯一稀疏索引
db.Student.ensureIndex({code:1},{unique:1,sparse:1});
獲取一個(gè)Collection上面的集合信息
// 單個(gè)Collection
db.Student.getIndexes();
// DB中所有的Index
db.system.indexes.find();
刪除索引
// 刪除在某個(gè)field上面的索引
db.Student.dropIndex({name:1});
// 根據(jù)索引名刪除
db.system.indexes.remove({name:"code_-1"})
如何修改索引呢队腐?沒有特定修改命令,一般是先刪除奏篙,然后創(chuàng)建新的索引柴淘。
系統(tǒng)運(yùn)行一段時(shí)間以后迫淹,隨著數(shù)據(jù)的累加,業(yè)務(wù)需求的變化为严,可能會(huì)需要對(duì)索引進(jìn)行重建(rebuild)敛熬,則可以做這個(gè)操作:
db.collection.reIndex()
rebuild會(huì)先刪除集合上的所有索引,包括_id索引第股,然后重建应民。這種操作往往和耗時(shí),最好在系統(tǒng)資源充足的時(shí)候做夕吻。
細(xì)節(jié)
1. 限制
mongodb對(duì)索引的使用和管理也有一些限制
索引key的總?cè)萘坎荒艽笥?024byte,否則以后的索引將創(chuàng)建不了
單個(gè)集合不能超過64個(gè)索引
單個(gè)索引的名字長(zhǎng)度(包括命名空間)不能超過125 個(gè)字符
復(fù)合索引最多只能作用在31個(gè)field上
一個(gè)查詢不能同時(shí)使用text and Geospatial 索引
上面列的只是一些大的限制诲锹,在具體場(chǎng)景中還有很多索引相互沖突,或者使用不當(dāng)造成索引無法命中的情況涉馅,所以還要看看更細(xì)節(jié)的一些東西归园。
2. 使用策略
2.1 _id 主鍵索引
這個(gè)是系統(tǒng)自動(dòng)創(chuàng)建的,不能刪除稚矿,除非你Drop掉整個(gè)Collection庸诱。這個(gè)效率是非常高的,對(duì)于一些數(shù)據(jù)量很大晤揣,但是沒有排序需求的集合(如日志表)桥爽,在分頁策略上應(yīng)該使用_id來進(jìn)行分頁。
2.2 single 單鍵索引
mongodb 不限制你在任何field上面創(chuàng)建單鍵索引昧识,但是一個(gè)查詢一次只能使用一個(gè)索引($or子句可以使用多個(gè))钠四,所以看看下面的情況會(huì)是這樣的:
//存在兩個(gè)索引:
{code:1},
{name:1}
//這里mongodb只會(huì)命中一個(gè)索引滞诺,具體是哪個(gè)由查詢分析器決定
db.Student.find({code:{$lt:10},name:{$regex:/^a/}}).explain();
{
"cursor" : "BtreeCursor name_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 4,
"nscannedAllPlans" : 4,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 46,
"indexBounds" : {
"name" : [
[
"a",
"b"
]
]
},
"server" : "pormatoMacBook-Pro.local:27017"
}
索引還存在排序問題形导,{a:1}升序 / {a:-1}降序
,但是對(duì)于單鍵索引习霹,排序的時(shí)候升序降序都會(huì)命中朵耕。如:
db.Student.find().sort({name:1});
db.Student.find().sort({name:-1});
2.3 復(fù)合索引
多數(shù)情況下,應(yīng)該考慮復(fù)合索引而非單鍵索引淋叶,因?yàn)閺?fù)合索引會(huì)包含部分單鍵索引阎曹。例如:
對(duì)于索引:
{a:1,b:1,c:1}
相當(dāng)于該集合擁有了:
{a:1}
, {a:1,b:1}
, {a:1,b:1,c:1}
但是:
{b:1}
,{c:1}
, {b:1,c:1}
是無法命中的。
如果排序也希望命中索引的話煞檩,這里分為兩種情況:
- 排序字段以索引開始鍵開頭
// 因?yàn)椴樵儣l件中不存在索引開始鍵(a:1)处嫌,要想命中索引,排序必須以索引開始鍵開頭
db.mycoll.find({b:{$gt:1}}).sort({a:1,b:1,c:1});
- 排序字段不以索引開始鍵開頭
db.mycoll.find({a:{$gt:1}}).sort({b:1,c:1});
當(dāng)然斟湃,排序里面還有更為細(xì)致的問題熏迹,就是查詢條件如果有索引field的精準(zhǔn)匹配(equal),則排序也能更簡(jiǎn)單:
db.mycoll.find({a:1}).sort({b:1});
同樣,復(fù)合索引也存在索引反序問題,這里和單鍵索引一樣凝赛,只有完全反序才能命中:
對(duì)于索引{a:1,b:-1}
, {a:-1,b:1}
是可以命中的注暗,反過來也成立坛缕。但是:{a:1,b:1}
或者{a:-1,b:-1}
是無法命中索引的。
3 MultiKey Index 多鍵索引
多鍵索引是作用在 array field上的element中的某個(gè)field上的索引捆昏。這個(gè)沒有太多的特別之處赚楚,唯一要注意的是,如果一個(gè)索引是復(fù)合多鍵索引
,那么這個(gè)索引的field中只能有一個(gè)array類型骗卜。例如:
{a:1,b:[{b1:1,b2:1}]
這個(gè)是Ok的宠页, {a:[a1:1,a2:1],b:[{b1:1,b2:1}]
這種索引則是非法的。
其它
mongdb中還存在一種Cover Index的說法寇仓。它發(fā)生在如下的情況中:
all the fields in the query are part of an index,
and
all the fields returned in the results are in the same index.
代碼
db.mycoll.find({a:{$lt:100}},{a:1,_id:0}});
這個(gè)時(shí)候查詢條件的field和 查詢域field 完全一樣举户,并且這個(gè)field剛好能命中索引的話,這個(gè)查詢效率將非常的高焚刺,因?yàn)閙ongodb不會(huì)再去硬盤進(jìn)行掃描敛摘,而是直接將Index信息返回。
這里需要知道的是如果在下面兩種情況下乳愉,Cover Index將無法生效
any of the indexed fields in any of the documents in the collection includes an array. If an indexed field is an array, the index becomes a multi-key index , index and cannot support a covered query.
數(shù)組field將直接會(huì)使索引變?yōu)槎噫I索引any of the indexed fields are fields in subdocuments. To index fields in subdocuments, use dot notation.
查詢域總是會(huì)返回整個(gè)子文檔的root節(jié)點(diǎn)
基本的索引類型就是這么多了兄淫,接下來還有Text , Geo ,hash等較為復(fù)雜的索引類型,這個(gè)在以后的文章中再來分析蔓姚。