Mongodb索引及查詢優化分析
創建索引
db.collection.createIndex(keys, options)
- 參數說明:
- keys: {FieldNameOne:ascending,… FieldNameN:ascending}: ascending 設為1 標識索引升序,-1降序
- options : 設置索引選項,如設置名稱、設置成為唯一索引
唯一(_id)索引
MongoDB都會自動生成一條唯一的_id字段
唯一索引會阻止應用插入被索引鍵上的值是重復值的documents
-
不能再已經有重復數據的字段上建立唯一索引
db.collections.createIndex({“FieldName”: 1或-1},{“unique”:true})
單鍵索引
-
在一個鍵上創建的索引就是單鍵索引
db.collection.createIndex({'fieldName':1/-1});
復合索引
查詢多個條件時,建立復合索引
-
在多字段上建唯一索引會強制要求復合鍵值的唯一性,而不是每個鍵的唯一性
db.collection.createIndex({'fieldName_one':1/-1,'fieldName_n..':1/-1});
-
總結:
- 查詢條件只是復合索引key中部分字段時,如果想要復合索引起到優化的作用則必須包含創建復合索引時指定的第1個字段;
- 可以指定在索引的所有鍵或者部分鍵上排序。但是,排序鍵的順序必須和它們在索引中的排列順序一致sort中指定的所有鍵的排序順序(例如遞增/遞減)必須和索引中的對應鍵的排序順序完全相同, 或者 完全相反。
多鍵索引
-
多鍵索引與單鍵索引創建形式相同,區別在于字段的值,如:數組
db.collection.createIndex({'arrayFieldName':1/-1});
稀疏索引
db.collection.createIndex({“FieldName”:1},{“sparse”:true})
-
在一個字段上創建稀疏索引,索引會跳過所有不包含被索引鍵(字段)的文檔在執行查詢 { 被索引鍵:{$exists:false}},不會使用該稀疏索引,除非顯示指定hint({被索引鍵:1})
db.scores.createIndex( { score: 1 } , {sparse:true} ) db.scores.find( { score:{$exists:false}}).hint({score:1}).explain()
-
總結
- 在某一個被創建了稀疏索引字段上執行exists:false查詢時,需要顯示指定hint,其索引才會起作用;而執行 exists:true查詢時,則不需要。
- 在字段上創建普通索引,如果文檔不含該字段這其索引值會被設為null,而稀疏索引會跳過該文檔;這就是說使用該索引掃描集合時稀疏索引會比普通索引少。
局部索引(Partial Index)
db.collection.createIndex(
{“FieldName”: 1/-1,…”FieldNameN”: 1/-1},
{“partialFilterExpression”:{partialFilterExpression }})
db.contacts.createIndex(
{ name: 1 },
{ partialFilterExpression: { name: { $exists: true } } }
)
- $eq
- $gt, $gte, $lt, $lte
- $exists: true
TTL(過期)索引
在一段時間后會過期的索引,在索引過期后,相應的數據會被刪除,適合存儲在一段時間之后會失效的數據;
存儲在過期索引字段的值必須是指定的時間類型,必須是ISODate或者ISODate數組,不能使用時間戳,否則不能自動刪除;
如果指定了ISODate數組,則按照最小的時間進行刪除;
過期索引不能是復合索引,因為不能指定兩個過期時間;
-
刪除時間是不精確的:刪除過程是由MongoDB的后臺進程每60s跑一次的,而且刪除也需要一定時間,所以存在誤差。
db.collection.createIndex({'dateTimeField':1},{expireAfterSeconds:100(秒)});
全文索引
對字符串與字符串數組創建全文課搜索的索引;
在MongoDB中每個數據集合只允許創建一個全文索引,不過這個全文索引可以針對一個、多個、全部的數據集合的字段來創建;
每次查詢只能指定一個$text查詢$text查詢不能出現在$nor查詢中;
-
查詢中如果包含了$text, hint不再起作用
db.file.find({$text:{$search:'mongo'},'status.pub':true},{ score: { $meta: "textScore" } }).sort( {score: { $meta: "textScore" }} )
地理空間索引
2D索引,用于存儲和查找平面上的點
-
2Dsphere索引,用于存儲和查找球面上的點
db.collection.createIndex({w:"2d"})
使用$near 查詢距離某個點最近的點 ,默認返回最近的100個點
-
可以使用$maxDistance:x 限制返回的最遠距離
db.collection.find({w:{$near:[x,y]}}) db.collection.find({w:{$near:[x,y],$maxDistance:z}})
使用$geoWithin 查詢某個形狀內的點
哈希索引
查詢性能分析
db.collection.find({}).explain("queryPlanner"/"executionStats"/"allPlansExecution")
db.file.createIndex({'tag.self':1})
db.file.find({'tag.self':{$in:['node']}}).explain("executionStats")
性能指標
- winningPlan.stage = FETCH(根據索引去檢索指定document )
- winningPlan.inputStage.stage = IXSCAN(索引掃描)
- totalKeysExamined 索引掃描條目
- totalDocsExamined 文檔掃描條目
- nReturned 查詢返回的條目
總結:
- 排序操作可以通過從索引中按照索引順序獲取文檔的方式來保證結果的有序性。如果查詢計劃器(planner)無法從索引中得到排序順序,那么它將需要在內存中排序(winningPlan.stage=SORT)結果。
- 在多個字段上做排序時需要使用復合索引