mongoDB的索引

1 索引

  • 索引一般可以極大的提升查詢的效率,若是沒有索引,MongoDB在讀取數據時必須掃描集合中的每一個文件並選取那些符合查詢條件的記錄。
  • 這種掃描全集合的查詢效率是很是低的,特別在處理大量的數據時,查詢能夠要花費幾十秒甚至幾分鐘,這對網站的性能是很是致命的。
  • 索引是特殊的數據結構,索引存儲在一個易於遍歷讀取的數據集合中,索引是對數據庫表中一列或多列的值進行排序的一種結構

2 創建索引

2.1 建立匿名索引

2.1.1 準備數據

  • users數據庫中的classOne集合中添加 1000000 條文檔
> use user
> for (var i = 1; i<= 1000000;i++) {
    users.push({name: 'Lily_' + i, num: i })
}
> db.classOne.insert(users);
/* BulkWriteResult({ "writeErrors" : [ ], "writeConcernErrors" : [ ], "nInserted" : 1000000, "nUpserted" : 0, "nMatched" : 0, "nModified" : 0, "nRemoved" : 0, "upserted" : [ ] })*/
複製代碼

2.1.2 查找{num: 1000000}文檔的過程分析

> db.classOne.find({num: 1000000}).explain(true)
{
	"queryPlanner" : {
		"plannerVersion" : 1,
		"namespace" : "user.classOne",
		"indexFilterSet" : false,
		"parsedQuery" : {...},
		"winningPlan" : {
			"stage" : "COLLSCAN",   // 掃描全部的數據 
			"filter" : {...},
			"direction" : "forward"
		},
		"rejectedPlans" : [ ]
	},
	"executionStats" : {
		"executionSuccess" : true,
		"nReturned" : 1,
		"executionTimeMillis" : 365,    // 本次查找執行時間的毫秒數
		"totalKeysExamined" : 0,
		"totalDocsExamined" : 1000000,
		"executionStages" : {
			...
		},
		"allPlansExecution" : [ ]
	},
	"serverInfo" : {
		...
	},
	"ok" : 1
}
複製代碼

從這個過程的解析對象中,咱們得知查找{num: 1000000}文檔,是經過COLLSCAN方式掃描的,執行的時間爲 365msmongodb

2.1.3 建立匿名索引

在常常按照文檔的倒序查找的應用場景中,咱們能夠經過創建索引來進行查找,以節約咱們的查找時間。數據庫

db.collection.ensureIndex(keys, options)
複製代碼
  • 創建索引
> db.classOne.ensureIndex({num: 1})
/* { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, // 添加本次索引以前的索引數 "numIndexesAfter" : 2, // 添加本次索引以後的索引數 "ok" : 1 } */
複製代碼
  • 創建索引後再次查找
> db.classOne.find({num: 1000000}).explain(true)
/* { "queryPlanner" : { ... "winningPlan" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", // 經過掃描索引進行查找 "keyPattern" : { "num" : 1 }, "indexName" : "num_1", // 若是沒有指定索引名稱的話, 默認格式爲 ‘字段_1’ 或者 ‘字段_-1’ , 1 表明正序, -1 表明 倒序 "isMultiKey" : false, "multiKeyPaths" : { "num" : [ ] }, ... } }, ... }, "executionStats" : { "executionSuccess" : true, "nReturned" : 1, "executionTimeMillis" : 6, // 本次執行時間的毫秒數爲 6ms !!! ... }, "serverInfo" : {...}, "ok" : 1 } */
複製代碼

創建索引以前用時 365 ms , 創建索引以後查找用時須要 6 ms, 用時大大的減小了。數組

2.2 建立命名索引

若是沒有指定索引名稱的話, 默認格式爲 fieldName_1 或者 fieldName_-1,若是想要自定義索引名稱的話,能夠在建立的時候指定名稱,以下:緩存

> db.classOne.ensureIndex({name: 1}, {name:' myIndexName'})
/* { "createdCollectionAutomatically" : false, "numIndexesBefore" : 2, "numIndexesAfter" : 3, "ok" : 1 } */
複製代碼

2.3 查看索引

> db.classOne.getIndexes()
/*
[
	{
		"v" : 2,
		"key" : {
			"_id" : 1
		},
		"name" : "_id_",    // 原始的 根據 _id 字段 生成的索引 
		"ns" : "user.classOne"
	},
	{
		"v" : 2,
		"key" : {
			"num" : 1
		},
		"name" : "num_1",   // 根據 num 字段 升序 建立的索引 
		"ns" : "user.classOne"
	},
	{
		"v" : 2,
		"key" : {
			"name" : 1
		},
		"name" : " myIndexName",   // 本身命名建立的索引
		"ns" : "user.classOne"
	}
]
*/
複製代碼

2.4 指定須要使用的索引

> db.classOne.find({num: "500000"}).hint({num:1}).explain(true)
複製代碼

2.5 刪除索引

db.collectionName.dropIndex(IndexName)  刪除指定的索引(IndexName)

db.collecitonName.dropIndex('*');       刪除全部索引
複製代碼

2.6 在後臺建立索引

db.collection.ensureIndex(keys, {background: true})
複製代碼

2.7 創建多鍵索引

mongodb能夠自動對數組進行索引bash

> db.classOne.insert({hobby:['basketball','football','pingpang']});
> db.classOne.ensureIndex({hobby:1});
> db.classOne.find({hobby:'football'},{hobby:1,_id:0}).explain(true);
複製代碼

2.8 複合索引

查詢的條件不止一個,須要用複合索引session

db.collection.ensureIndex({name:1,num:1});
複製代碼

2.9 過時索引

在必定的時間後會過時,過時後相應數據數據被刪除,好比session、日誌、緩存和臨時文件數據結構

> db.classTwo.insert({time:new Date()});
> db.classTwo.ensureIndex({time:1},{expireAfterSeconds:10});
複製代碼

note性能

  • 索引字段的值必須Date對象,不能是其它類型好比時間戳
  • 刪除時間不精確,每60秒跑一次。刪除也要時間,因此有偏差。

2.10 全文索引

大篇幅的文章中搜索關鍵詞,MongoDB爲咱們提供了全文索引網站

2.10.1 建立全文索引

db.colleciton.ensureIndex({field: 'text'})
複製代碼

note: text- 建立全文索引,1 - 升序索引,2 - 降序索引spa

2.10.2 usage

語法

  • $text: 表示要在全文索引中查東西
  • $search: 後邊跟查找的內容, 默認所有匹配

舉個栗子

  • 1 準備數據
// 原始數據
{ "_id" : ObjectId("5afa93eae82637e49ce12077"), "name" : "Lily", "content" : "I am a girl" }
{ "_id" : ObjectId("5afa93f6e82637e49ce12078"), "name" : "Tom", "content" : "I am a boy" }
{ "_id" : ObjectId("5afa9561e82637e49ce12079"), "name" : "Carl", "content" : "I do not know boy girl" }
複製代碼
  • 2 建立全文索引 根據content字段建立一個全文索引
db.classThree.ensureIndex({content: 'text'})
複製代碼
  • 3 根據索引查詢數據
// 查找包含 ‘girl’ 的文檔
> db.classThree.find({$text: {$search: 'girl'}})
// { "_id" : ObjectId("5afa93eae82637e49ce12077"), "name" : "Lily", "content" : "I am a girl" }


// 查找包含 ‘boy’ 的文檔
> db.classThree.find({$text: {$search: 'boy'}})
// { "_id" : ObjectId("5afa93f6e82637e49ce12078"), "name" : "Tom", "content" : "I am a boy" }


// 查找包含 ‘girl’ 或者 ‘boy’ 的文檔(屢次查找是 與 的關係)
> db.classThree.find({$text: {$search: 'boy girl'}})
/* { "_id" : ObjectId("5afa93eae82637e49ce12077"), "name" : "Lily", "content" : "I am a girl" } { "_id" : ObjectId("5afa9561e82637e49ce12079"), "name" : "Carl", "content" : "I do not know boy girl" } { "_id" : ObjectId("5afa93f6e82637e49ce12078"), "name" : "Tom", "content" : "I am a boy" } */


// 查找僅包含‘girl’ 不包含‘boy’的文檔
> db.classThree.find({$text: {$search: 'girl -boy'}})
// { "_id" : ObjectId("5afa93eae82637e49ce12077"), "name" : "Lily", "content" : "I am a girl" }


// 就是要查找包含 ‘girl boy’ 字符的文檔(須要轉義)
> db.classThree.find({$text: {$search: '\"boy girl\"'}})
// { "_id" : ObjectId("5afa9561e82637e49ce12079"), "name" : "Carl", "content" : "I do not know boy girl" }
複製代碼
  • 4 note

屢次查找,多個關鍵字爲或的關係,中間以空格隔開

支持轉義符的,用\斜槓來轉義

3 二維索引

mongodb提供強大的空間索引能夠查詢出必定落地的地理座標

3.1 建立 2d 索引

db.collection.ensureIndex({field:'2d'}, options)
複製代碼

3.2 舉個栗子

  • 1 準備數據
{ "_id" : ObjectId("5afaa078e82637e49ce1207a"), "gis" : [ 1, 1 ] }
{ "_id" : ObjectId("5afaa078e82637e49ce1207b"), "gis" : [ 1, 2 ] }
{ "_id" : ObjectId("5afaa078e82637e49ce1207c"), "gis" : [ 1, 3 ] }
{ "_id" : ObjectId("5afaa078e82637e49ce1207d"), "gis" : [ 2, 1 ] }
{ "_id" : ObjectId("5afaa078e82637e49ce1207e"), "gis" : [ 2, 2 ] }
{ "_id" : ObjectId("5afaa078e82637e49ce1207f"), "gis" : [ 2, 3 ] }
{ "_id" : ObjectId("5afaa078e82637e49ce12080"), "gis" : [ 3, 1 ] }
{ "_id" : ObjectId("5afaa078e82637e49ce12081"), "gis" : [ 3, 2 ] }
{ "_id" : ObjectId("5afaa078e82637e49ce12082"), "gis" : [ 3, 3 ] }
複製代碼

以下圖:

2d索引

  • 2 建立 2d 索引
> db.map.ensureIndex({gis:'2d'})
/* { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 } */
複製代碼
  • 3 查詢距離[1,1]最近的四個點
> db.map.find({gis:{$near: [1,1]}}).limit(4)
/* { "_id" : ObjectId("5afaa078e82637e49ce1207a"), "gis" : [ 1, 1 ] } { "_id" : ObjectId("5afaa078e82637e49ce1207b"), "gis" : [ 1, 2 ] } { "_id" : ObjectId("5afaa078e82637e49ce1207d"), "gis" : [ 2, 1 ] } { "_id" : ObjectId("5afaa078e82637e49ce1207e"), "gis" : [ 2, 2 ] } */
複製代碼

查詢結果以下圖:

near

  • 4 查詢以點[1,2]和點[3,3]爲對角線的正方形中的全部的點
> db.map.find({gis: {$within:{$box: [[1,2],[3,3]]}}})
/* { "_id" : ObjectId("5afaa078e82637e49ce1207b"), "gis" : [ 1, 2 ] } { "_id" : ObjectId("5afaa078e82637e49ce1207e"), "gis" : [ 2, 2 ] } { "_id" : ObjectId("5afaa078e82637e49ce1207c"), "gis" : [ 1, 3 ] } { "_id" : ObjectId("5afaa078e82637e49ce1207f"), "gis" : [ 2, 3 ] } { "_id" : ObjectId("5afaa078e82637e49ce12081"), "gis" : [ 3, 2 ] } { "_id" : ObjectId("5afaa078e82637e49ce12082"), "gis" : [ 3, 3 ] } */
複製代碼

查詢結果以下圖:

box

  • 5 查出以[2,2]爲圓心,以1 爲半徑爲規則下圓心面積中的點
> db.map.find({gis: {$within:{$center: [[2,2],1]}}})
/* { "_id" : ObjectId("5afaa078e82637e49ce1207b"), "gis" : [ 1, 2 ] } { "_id" : ObjectId("5afaa078e82637e49ce1207d"), "gis" : [ 2, 1 ] } { "_id" : ObjectId("5afaa078e82637e49ce1207e"), "gis" : [ 2, 2 ] } { "_id" : ObjectId("5afaa078e82637e49ce1207f"), "gis" : [ 2, 3 ] } { "_id" : ObjectId("5afaa078e82637e49ce12081"), "gis" : [ 3, 2 ] } */
複製代碼

查詢結果以下圖:

center

note: [1,1]等角落裏的座標與[2,2]的座標距離是√2

4 索引使用的注意事項

  • 1爲正序 -1爲倒序
  • 索引雖然能夠提高查詢性能,但會下降插件性能,對於插入多查詢少不要創索引
  • 數據量不大時不須要使用索引。性能的提高並不明顯,反而大大增長了內存和硬盤的消耗。
  • 查詢數據超過表數據量30%時,不要使用索引字段查詢
  • 排序工做的時候能夠創建索引以提升排序速度
  • 數字索引,要比字符串索引快的多
相關文章
相關標籤/搜索