mongodb索引及查詢優化分析

weixin_34007291發表於2017-10-27

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)結果。
  • 在多個欄位上做排序時需要使用複合索引

相關文章