MongoDB索引的管理和型別
MongoDB的索引與mysql的索引大致相同,但是由於MongoDB的特有性,比如文件可能不會存在某一個欄位,文件有巢狀以及陣列型別,所以也會有些許差異。為了測試資料,和demo的使用,單節點上建立一個1千萬的文件,如下:
for(i=0; i<1000000; i++) {
db.user.insert({"i":i,"username":"user"+i,"age":Math.floor(Math.random()*120),
"created":new Date()});
}
一、MongoDB索引的建立與刪除(管理)
1、MongoDB索引的建立
MongoDB的索引底層實現原因與Mysql大致一直,比如都使用數的大致特點等。所以可以為單個索引,唯一索引,符合索引等。新建索引是比較費時的,特別是在一個存在大量資料的集合上,預設情況下,在建立索引的時候,會阻塞所有的讀和寫請求,一直到索引建立完成;但是也可以使用background選項來讓其在沒有請求進入的情況下才進行建立索引操作,但是任然對應用程式的影響較大,而且會加長建立索引的時間。建立索引的方式如下:
db.user.ensureIndex({"a":1, "b": -1}); # user為集合名稱,a,b為集合的欄位,而1和-1為索引的方向(1正序,-1倒序)
db.user.getIndexes(); # 檢視當前集合上已經建立的索引, _id為預設建立的唯一索引
索引的建立後會儲存在system.indexes保留集合中,不能對集合進行刪除或者修改只能通過ensureIndex(建立索引)和dropIndex(銷燬索引)。而集合的每一個索引的都是唯一表示,並且一般會預設使用以下方式進行名稱:
keyName1_dir1_keyName2_dir2; # 如剛才建立的username_1, 即在username上建立的一個正向的單個索引
2、銷燬索引
db.user.dropIndex("username_1"); # 根據索引的唯一名稱對索引進行刪除
二、MongoDB索引的型別
1、單個索引
上面建立索引的時候就是建立了一個單個索引,索引單個索引的建立和銷燬如上。只是需要注意單個索引的排序鍵方向是無所有的,當建立一個單個索引正向排序,查詢的時候MongoDB可以簡單的從反方向進行讀取索引即可。
2、複合索引
1)、複合索引
MongoDb的符合索引的特點與MySQL的符合索引一樣,遵從最左原則才能使用,可以使用範圍查詢。因為底層都是基於B或者B+樹實現,所以不多做深究,建立方式如下:
db.user.ensureIndex({"username":1,"age":-1}); # 建立一個使用者名稱稱正序,年齡反序的符合索引
2)、覆蓋索引需要注意事項
第一、索引方向
單個索引的的時候索引的方向是無關緊要的,但是當多個條件查詢並且進行排序的時候,則索引的方向則比較重要,最好是保證與查詢的方向一致(比如 name asc,age desc),但是在多個索引的時候,顯示出來的排序方向與他們都乘以-1後的方向是等價的,即相當於單個索引的反向查詢了(如{"username":1,"age":-1,"created":1}與{"username":-1,"age":1,"created":-1}效果一致)。
第二、覆蓋索引
覆蓋索引的概念與mysql完全一致,當需要查詢的條件與返回的欄位都是索引的欄位,即在索引數中就可以返回資料,則優先使用覆蓋索引(可見mongo使用的索引方式類似於mysql的innerdb,使用的聚集索引,不需要再根據資料的地址資訊去查詢)。如果是使用了覆蓋索引則,查詢執行計劃的時候,"indexOnly"欄位值為true。
3、唯一索引
1) 、單個唯一索引
唯一索引與mysql的大致相同,但是由於某些欄位可能不存在鍵或者只為null,所以會有些許的不同。唯一索引的建立方式入下:
db.user.ensureIndex({"username":1},{"unique":true}); # 在username欄位上建立一個正向的唯一索引
在建立索引的時候明顯感覺比之前建立單個索引慢很多,就是由於建立的時候需要檢查其唯一性。而在所以建立之後發現已經存在兩個索引,還有一個就是特殊的_id索引,就是一個唯一索引,只是該索引不能進行刪除操作。所以在沒有必要的情況下可以直接使用mongoDB的_id的值,如果是自己去實現的話在插入的時候會檢查唯一性,會有效能影響(MongoDB的欄位生成主鍵與ES的主鍵非常的類似,會有效能優化)。
由於會檢查唯一性,所以在建立索引的時候可能會失敗,或者在建立好之後插入文件的時候也可能失敗。在建立唯一索引之前可以使用聚合API查詢一下是否存在重複的資料,若是資料非常重要則需要先備份和資料的預處理。否則可以使用dropDups可選項,將只保留一條重複的資料。如下:
db.user.ensuerIndex({"username":1},{"unique":true , "dropDups":true}); # 不管怎麼樣,一定先備份資料
還有一點需要注意的是,唯一索引的儲存值不能超過1024KB,否則不會報錯也不會受唯一約束。並且很難對問題進行排查。
2)、複合唯一索引
複合唯一索引也是專案中經常會遇到的需求,即單個值可以不唯一,但是組合只能唯一。建立方式如下:
db.user.ensure({"username":1,"age":1},{"unique":true}); # 則使用者名稱和年齡的組合值需要唯一,當然這是一個偽需求
4、稀疏索引
1)、稀疏索引
在理解稀疏索引之前可以看一個
由於MongoDB在的鍵可能會不存在,所以在查詢資料的時候並不像mysql一樣肯定會返回資料。並且使用$exists查詢資料的話不會使用索引。很多時候我們可能不需要返回不存在該欄位的資料,如下:
所以必要的情況下可以在該欄位上新增稀疏索引,則在使用索引的情況下,快速的返回資料滿足需求,建立稀疏索引並執行之前的查詢操作,如下:
db.sparsedemo.ensureIndex({"sparse-field":1},{"sparse":true}); # 建立一個稀疏索引
2)、稀疏唯一索引
很多時候我們的需求是該欄位要不不存在,要存在則一定是唯一的(比如使用者的郵箱)。所以這時候需要同時滿足稀疏索引和唯一索引,建立稀疏索引的方式如下:
db.sparsedemo.ensureIndex({"sparse-field":1},{"unique":true,"sparse":true}); # 建立稀疏唯一索引