1. 程式人生 > >我叫Mongo,幹了「索引探索篇」提升我的效率,值得您擁有

我叫Mongo,幹了「索引探索篇」提升我的效率,值得您擁有

這是mongo第四篇“索引探索”,後續會連續更新4篇

 

   mongodb的文章總結上會有一系列的文章,順序是先學會怎麼用,在學會怎麼用好,戒急戒躁,循序漸進,跟著我一起來探索交流。通過上三篇的介紹,我相信大家對我在使用上已經很溜啦,但是在實際使用中還需要注重效率提升,本文章探索索引,就是為提升效率為出發點,本文的介紹順序是:索引簡介->索引原理->索引型別->索引與查詢結合使用->小結,讓我們一起來一步一步的探索吧。​

01

     索引簡介

 

  Mongodb的索引和其它關係型資料庫索引很類似,索引是一個儲存結構,其儲存的內容是資料文件持久化的位置資訊。一個數據集合和一本書來對比,那麼索引就是書對應的目錄,其作用就是加快查詢效率。索引在加快查詢效率的同時,在更新、刪除、新增資料時也會影響資料變更效率,因為每一次資料變更都會更新一次索引。所以在索引使用時也需要慎重。

Mongodb索引的基本命令包括:

新增索引:createIndex({欄位:排序方式},{可選引數})

刪除索引:dropIndex({欄位:排序方式})

檢視索引:getIndexes()

先不管索引為什麼能夠提高查詢效率,降低資料變更效率,先來一個例項。為了體現效果,這次我整的有點狠,直接初始化了300多萬條資料,演示步驟如下:

資料初始化:

for(var i=0;i<3000000 ;i++)

{
     db.user.insert({
        name:"我叫"+i,
        age:i%10,  
        from:i%10000
   })
}        

  

  // 上面的資料有一個特點age的值就10個,from的值有10000個。下面分別對兩個欄位加上索引,並通過實際的執行語句來看效果。

給user表的age新增一個索引(age升序)

db.user.createIndex({age:1})

給user表的from新增一個索引(from升序)

db.user.createIndex({from:1})

 

 

   其實我們都知道索引能夠提高查詢效率,估計很少親自測試一把,通過測試是不是有一種爽歪歪的感覺。根據實際操作結果我們先得出幾點小小的結論:

  • 當欄位的值是有限的一些值時,其實有無索引對效率無影響;
  • 當欄位的值重複資料少時,索引的查詢效率明顯提高几百倍;
  • 當查詢結果需要排序時,有索引比沒索引的效率高50倍左右;
  • 當更新時,有索引的效率低於無索引;
  • 所以在新增索引時針對欄位值是有限的值時,就沒必要新增索引,當經常需要用於排序的欄位可以考慮新增索引。

  以上的幾個結論,也是我通過實際資料操作得出的,如果有不準確的地方,希望指點改正,謝謝!

  先把結論得到這兒,下面我們在一步一步的剖析索引。

 

02

     索引原理

  Mongdb資料通過儲存引擎持久化以後,其實在磁碟中就是一個一個的檔案,每一個檔案都對應一個位置資訊。索引就是這一些檔案位置資訊與索引欄位值的對應關係的有序資料集合,索引採用btree的結構持久化儲存。在建立索引後,資料在查詢的時,直接索引資料集合查詢,然後在根據對於的位置資訊操作對應的資料詳情,避免了全表掃描,同時查詢出的資料本來就是有序的資料,也避免了因為排序導致的效能損失。

  這樣我們就不難理解上面得出的幾點結論了:因為索引查詢避免了全表資料掃描,所有查詢效率高;因為索引本身就已經是有序的資料,所以根據索引欄位排序效率明顯提高;因為索引會單擊儲存,一旦資料有變更,都需要同時更新索引資料,所有資料更新時有索引的效率低,同時索引也會增加額外的儲存開銷。

03

     索引型別

  MongoDB支援多種型別的索引,包括單欄位索引、複合索引、多key索引、文字索引等,每種型別的索引有不同的使用場合。

  單欄位索引:

  單欄位索引其實很好理解,文章開始我們建立的例項就是單欄位索引,簡單的所說就是針對某一個欄位建立一個索引,達到提高索引欄位的查詢效率。Mongdb預設_id欄位建立單欄位唯一索引。

 

 格式:db.collectionName.createIndex({索引欄位:1升序-1降序} )

  例項:對集合user的欄位age添加升序索引

  db.user.createIndex({age:1})

   

  複合索引:

  複合索引是針對單欄位索引的升級版,複合索引就是聯合多個欄位建立索引,也是我們常說的聯合索引。複合索引在資料儲存上,首先根據第一欄位排序、然後當第一欄位值相同時在以第二欄位排序、依次類推第N欄位。複合索引能夠滿足以下兩個場景的查詢需要:根據複合索引多個欄位組合查詢;根據所有字首欄位查詢,也就是所有欄位的順序的第一個至第N個的字首欄位查詢。

格式:db.collectionName.createIndex({索引欄位1:排序, 索引欄位2:排序} )

例項:對集合user新增欄位from降序、age升序索引

db.user.createIndex({from:-1,age:1 })

以下情況可以使用到索引:

db.user.find({from:20,age:8})、db.user.find({from:20})

以下情況不能使用索引:

db.user.find({age:8,from:20})、db.user.find({age:8})

  根據複合索引的使用情況得出以下幾點小結論:

  • 索引使用順序一定要和索引建立順序保持一致;
  • 當索引欄位不完全組合查詢時,需要前序欄位連續;
  • 建立索引時最好取值豐富的欄位在前。

  多key索引:

  多key索引是指建立的索引欄位為陣列,多key索引會為陣列的每個元素建立一條索引,使用場景就是針對欄位值是陣列的查詢。有了前面的基礎,這一個就很好理解,就不在詳細描述了。

  文字索引:

  文字索引,簡單的說就是針對文字資料建立索引,比如,文章資訊表,如果需要根據文章關鍵詞檢索,那麼就可以對文章欄位建立文字索引。格式為:db.collectionName.createIndex({索引欄位1: "text" } )

04

   索引額外屬性說明 

  createIndex建立索引時,該方法有兩個引數,第一個引數就是索引欄位,上面已經說了,第二個引數就是索引的額外屬性,下面我們就說說索引額外屬性資訊。索引額外屬性包括:唯一索引、TTL索引、稀疏索引。

  TTL索引:

  TTL索引屬性是修飾當文件儲存自定時間,當超出指定時間後,資料被被自動刪除,使用場景為資料只儲存指定時間,如:日誌資料,關鍵詞為expireAfterSecs,格式為:db.collectionName.createIndex({索引欄位1: "text" }, {"expireAfterSecs": 失效時間單位為秒})。

TTL索引幾點注意事項:

  • TTL只使用於時間欄位
  • TTL不使用於聯合索引
  • TTL如果對於索引值是陣列,那麼只要其中一個值滿足要求就自動刪除

  唯一索引 (unique index):

 保證索引對應的欄位不會出現相同的值,比如_id索引就是唯一索引。格式為:db.collectionName.createIndex({索引欄位1: "text" }, {"unique": true})。
 

  部分索引 (partial index):

  只針對符合某個特定條件的文件建立索引,3.2版本才支援該特性。關鍵詞為partialFilterExpression,

 

 格式為:db.collectionName.createIndex({索引欄位1: "text" }, {"partialFilterExpression": {資料滿足條件表示式}})。

  比如:對錶user只有age=9的資料建立索引

  db.user.createIndex({age:1},

  {"partialFilterExpression":{age:9}})

   

  稀疏索引(sparse index):

  只針對存在索引欄位的文件建立索引,可看做是部分索引的一種特殊情況。關鍵詞為:sparse,格式為:db.collectionName.createIndex({索引欄位1: "text" }, {"sparse": true})。
 

06

     索引優化(profiling)

 其實我們在建集合的時候,很多時候最開始是不知道那一些欄位需要新增索引,是需要根據後續的實際使用場景來動態建立,那麼這就會有一個問題,如果監控哪一些欄位需要新增或是刪除索引,可通過檢測每一次操作結果的響應時間長短來動態建立索引,mongdb提供了一個profiling來動態檢測執行響應情況。

MongoDB支援對DB的請求進行profiling,目前支援3種級別的profiling。

  • 0: 不開啟profiling
  • 1: 將處理時間超過某個閾值(預設100ms)的請求都記錄到DB下的system.profile集合 (類似於mysql、redis的slowlog)
  • 2: 將所有的請求都記錄到DB下的system.profile集合(生產環境慎用)

  通常,生產環境建議使用1級別的profiling,並根據自身需求配置合理的閾值,用於監測慢請求的情況,並及時的做索引優化。

開啟profiling命令:db.setProfilingLevel(1,120 );
查詢profil記錄資訊:db.system.profile.find()

    最終通過查詢出來的記錄資訊,對索引進行優化。

07

小結

            Mongdb在提升查詢效率上是很有幫助,但是在實際使用中也不要濫用,否則會適得其反,下面總結幾點,供參考:

    • 索引建立時最好作用於取值豐富的欄位,有限值的欄位就沒必要新增索引;
    • 經常排序的欄位,可以考慮新增索引;
    • 一個集合中索引的個數不是越多越好,需要根據實際情況來定;
    • 執行介面慢,有可能是缺少索引(查詢慢),也有可能是索引使用不當(編輯慢);
    • 複合索引在使用時,一定要結合索引欄位的順序使用。
  • END
    原創不易,感謝掃描支援,獲取更多精彩,謝謝: