MongoDB資料庫索引

来源:http://www.cnblogs.com/xiaohuochai/archive/2017/07/18/7198461.html
-Advertisement-
Play Games

[1]引入 [2]概述 [3]索引設置 [4]索引種類 [5]全文索引 [6]地理位置索引 ...


前面的話

  索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB在讀取數據時必須掃描集合中的每個文件並選取那些符合查詢條件的記錄。這種掃描全集合的查詢效率是非常低的,特別在處理大量的數據時,查詢可以要花費幾十秒甚至幾分鐘,這對網站的性能是非常致命的。本文將詳細介紹MongoDB資料庫索引

 

引入

  索引能夠提高查詢效率,如何體現呢?接下來使用性能分析函數explain()來進行分析說明

  首先,插入10萬條數據

  接著,不創建索引,來尋找time範圍在100和200之間的文檔

  由圖中所知,totalDocsExamined值為100000,表示查找了100000個文檔;nReturned值為101,表示返回了101個文檔;executionTimeMillis值為39,表示花費了39ms

  下麵,我們在time欄位上建立索引

  再次,尋找time範圍在100和200之間的文檔

  由圖可知,totalDocsExamined和nReturned值都是101,executionTimeMillis值為0,相當於從101個文檔中,找到了101個文檔,查找的速度趨近於0。由此可見,使用索引極大地提升了查詢速度

 

概述

  索引是特殊的數據結構,以易於遍歷的形式存儲數據集的一小部分。 索引存儲特定欄位或一組欄位的值,按照索引中指定的欄位值排序

  使用索引,可以加快索引相關的查詢,也相應地帶來一些壞處

  1、增加磁碟空間的消耗。在索引比較多的情況下,索引文件所占據的空間有可能超過數據本身

  2、在寫入數據或更新數據時,對索引的維護一般是寫之外的另一條邏輯,一定程度上,會降低寫入性能

  但是,為了查詢的高效,這些影響是值得的。有很多情況下,系統的性能下降,與不合理的索引創建有關。所以,合理的創建索引,可以減少索引帶來的不好的影響

 

索引設置

【getIndexes()】

  使用getIndexes()方法來查詢索引

db.collection_name.getIndexes()

  由下圖可知,有"_id"和"time"兩個索引

【createIndex()】

db.COLLECTION_NAME.createIndex({KEY:1})

  語法中Key值為要創建的索引欄位,1為指定按升序創建索引,如果想按降序來創建索引指定為-1即可

 

  當然,也可以創建多個索引欄位

db.COLLECTION_NAME.createIndex({k1:1,k2:1})

  在MongoDB3.0版本之前,使用的是ensureIndex()方法,現在ensureIndex()方法依然可以使用,只是createIndex()方法的別名

  如果文檔較多,創建索引需要耗費一定的時間。如果系統負載較重,且有很多已經存在的文檔,不能直接使用這個命令進行創建,需要在使用資料庫之前,就將索引創建完畢。否則,嚴重影響資料庫的性能

  [註意]索引可以重覆創建,如果對已經存在的索引再次創建,會直接返回成功

  createIndex() 接收可選參數,可選參數列表如下:

Parameter     Type      Description
background    Boolean    建索引過程會阻塞其它資料庫操作,background可指定以後臺方式創建索引,預設值為false
unique        Boolean    建立的索引是否唯一。指定為true創建唯一索引。預設值為false
name          string     索引的名稱。如果未指定,MongoDB通過連接索引的欄位名和排序順序生成一個索引名稱
dropDups      Boolean    在建立唯一索引時是否刪除重覆記錄,指定 true 創建唯一索引。預設值為 false
sparse        Boolean    對文檔中不存在的欄位數據不啟用索引;如果設置為true,索引欄位中不會查詢出不包含對應欄位的文檔。預設值為false
v             index version    索引的版本號。預設的索引版本取決於mongod創建索引時運行的版本
weights       document   索引權重值,數值在 1 到 99,999 之間,表示該索引相對於其他索引欄位的得分權重
expireAfterSeconds  integer   指定一個以秒為單位的數值,完成 TTL設定,設定集合的生存時間
default_language    string    對於文本索引,該參數決定了停用詞及詞乾和詞器的規則的列表。 預設為英語
language_override   string    對於文本索引,該參數指定了包含在文檔中的欄位名,預設值為language
db.db_coll1.createIndex({time:1},{background:true})

【dropIndex()】

  使用db.collection_name.dropIndex({key:1})方法可以刪除指定索引

db.collection_name.dropIndex({key:1})

  [註意]_id索引無法被刪除

  除了使用鍵值對來刪除索引,還可以使用其name值來刪除索引

  如下所示,{time:1}的name值為"time_1",使用db.db_coll1.dropIndex("time_1")也可以刪除索引

【dropIndexes()】

  使用db.collection_name.dropIndexes()方法可以刪除所有索引

db.collection_name.dropIndexes()

 

索引屬性

【TTL】

  過期索引又稱為TTL索引,是一種特殊類型的單欄位索引,主要用於當滿足某個特定時間之後自動刪除相應的文檔。也就是說集合中的文檔有一定的有效期,超過有效期的文檔就會失效,會被移除。也即是數據會過期。過期的數據無需保留,這種情形適用於如機器生成的事件數據,日誌和會話信息等等

  同樣地,過期索引使用createIndex()方法來創建,但它支持第二個參數expireAfterSeconds,用來指定多少秒過期或者包含過期日期值的數組

 db.eventlog.createIndex( { x: 1 }, { expireAfterSeconds: 3600 } )

  以下示例中,在60s後,會刪除time文檔

  使用過期索引,有以下幾點註意事項

  1、存儲在過期索引欄位的值必須是指定的時間類型。必須是ISODate或者ISODate數組,不能使用時間戳,否則不能被自動刪除

  以下示例中time設置了ISODate類型的值,該值到60s後會被自動刪除

  以下示例中,time設置了時間戳,該值到60s後無法被刪除

  2、如果指定了ISODate時間數組,則按照最小的時間進行刪除

  3、過期索引不能是複合索引

  4、刪除時間是不精確的。刪除過程是由後臺程式每60s跑一次,而且刪除也需要一些時間,存在誤差。所以,如果設置的到期時間與當前時間的間隔小於60s,則文檔最少也要60s才能被刪除

【唯一性】

  索引的屬性可以具有唯一性,即唯一索引,只要設置索引屬性中的unique為true即可,預設為false。唯一索引用於確保索引欄位不存儲重覆的值,即強制索引欄位的唯一性。預設情況下,mongodb的_id欄位在創建集合的時候會自動創建一個唯一索引

db.collection_name.createIndex({},{unique:true})

  如下圖所示,在預設情況下,不是唯一索引

  在設置unique:true後,不能插入重覆的值

常見錯誤

  如下圖所示,設置的a欄位為唯一索引,b欄位也無法輸入重覆的值。這是因為設置a欄位為唯一索引,插入數據b:10,相當於a:null,再插入b:10時,相當於又插入了a:null。而a:null和a:null是重覆的,而a欄位是唯一索引,無法重覆。所以,無法插入重覆的b:10

【稀疏性】

  索引的屬性可以具有稀疏性,即稀疏索引,只要設置索引屬性中的sparse為true即可,預設為false

db.collection_name.createIndex({},{sparse:true})

  稀疏性的不同代表了MongoDB在處理索引中存在但文檔中不存在的欄位的兩種不同的方法

  稀疏索引,也稱為間隙索引就是創建索引的索引列在某些文檔上列不存在,導致索引存在間隙。

  假設,在一個集合中,創建了x欄位上的索引。但是,插入的文檔中並不包含x欄位。在預設情況下,MongoDB依然會為這條不存在的欄位創建索引。如果把這條索引創建為稀疏索引,則這條索引將不會被使用

  如果數據集合中很多文檔在創建索引的欄位上並沒有值,使用稀疏索引可以減少磁碟占用,且提高插入速度

$exits

  使用稀疏索引時,可能會帶來一些隱患。MongoDB提供了一種$exits操作符,$exits表示欄位是否存在

  由下圖所示,創建了{m:1}的稀疏索引,使用find()方法查找不存在m欄位的文檔時,結果出現了。是因為,MongoDB並沒有使用稀疏索引來查詢

  如果使用hint()方法強制使用稀疏索引來查找索引上存在而文檔中不存在的欄位,則沒有結果。再次說明稀疏索引不能用來查找索引上存在,但文檔里不存在的欄位

 

索引種類

  MongoDB支持基於集合文檔上任意列創建索引。預設情況下,所有的文檔的_id列上都存在一個索引。基於業務的需要,可以基於一些重要的查詢和操作來創建一些額外的索引。這些索引可以是單列,也可是多列(複合索引),多鍵索引,地理空間索引,全文索引等

  MongoDB支持6種索引,包括

  1、_id索引

  2、單鍵索引

  3、多鍵索引

  4、複合索引

  5、全文索引

  6、地理位置索引

【_id索引】

  _id索引是絕大多數集合預設建立的索引,對於每個插入的數據,MongDB都會自動生成一條唯一的_id欄位

  由下圖所示,在未插入任何索引之前,已經存在_id索引

【單鍵索引】

  單鍵索引是最普通的索引,與_id索引不同,單鍵索引不會自動創建

  比如,一條記錄,形式為{x:1,y:2,z:3},在x欄位上建立索引,之後就可以使用x為條件進行查詢

【多鍵索引】

  在MongoDB中可以基於數組來創建索引。mongodb為數組每一個元素創建索引值。多鍵索引支持數組欄位的高效查詢。多鍵索引能夠基於字元串,數字數組以及嵌套文檔進行創建

  多鍵索引與單鍵索引創建形式相同,區別在於欄位的值。單鍵索引的值為單一的值,如一個字元串、數字或日期。多鍵索引的值具有多個記錄,如一個數組

  如果mongoDB中插入數組類型的多鍵數據,索引是自動建立的,無需刻意指定。但是,使用getIndexes()方法並沒有多鍵索引,除非顯式地創建多鍵索引

【複合索引】

  MongoDB支持複合索引,即將多個鍵組合到一起創建索引。該方式稱為複合索引,或者也叫組合索引,該方式能夠滿足多鍵值匹配查詢使用索引的情形。其次複合索引在使用的時候,也可以通過首碼法來使用索引

  [註意]任意複合索引欄位不能超過31個

  比如,插入{x:1,y:2,z:3}的記錄,當需要按照x與y的值進行查詢時,就需要創建x與y的複合索引。接著,就可以使用x和y作為條件進行查詢

db.db_coll1.createIndex({x:1,y:1})
db.db_coll1.createIndex({x:-1,y:1})
db.db_coll1.createIndex({x:-1,y:-1})
db.db_coll1.createIndex({x:1,y:-1})
db.db_coll1.createIndex({y:1,x:1})
db.db_coll1.createIndex({y:-1,x:1})
db.db_coll1.createIndex({y:-1,x:-1})
db.db_coll1.createIndex({y:1,x:-1})

  複合索引創建時按升序或降序來指定其排列方式。對於單鍵索引,其順序並不是特別重要,因為MongoDB可以在任一方向遍歷索引。對於複合索引,按何種方式排序能夠決定該索引在查詢中能否被使用到

  x與y的複合索引共包括以上8種情況,x和y的先後次序不同,升序或降序不同 ,都會產生不同的索引。而查詢優化器,會使用我們建立的這些索引來創建查詢方案,最終選擇出最優的索引來查詢數據

  索引首碼指的是複合索引的子集

  假如存在如下索引

{ "item": 1, "location": 1, "stock": 1 }

  那存在下列索引首碼

{ item: 1 }
{ item: 1, location: 1 }

  在MongoDB中,下列查詢過濾條件情形中,索引將會被使用到

item欄位
item欄位 + location欄位
item欄位 + location欄位 + stock欄位
item欄位 + stock欄位(儘管索引被使用,但不高效)

  以下過濾條件查詢情形,索引將不會被使用到

location欄位
stock欄位
location + stock欄位

 

全文索引

【創建】

  全文索引也叫做文本索引,常見於搜索框中。我們在搜索框中輸入關鍵詞,比如 "HTML",不僅標題中帶有"HTML"的文章會被搜索出來,而且文章中存在"HTML"的文章也會被搜索出來

  為了索引一個存儲字元串或者字元串數組的鍵,需要在創建選項中包含這個鍵並指定為 "text" ,如下:

db.reviews.createIndex( { comments: "text" } )

  如果需要在多個欄位上創建全文索引,則可以複合索引

db.reviews.createIndex(
   {
     subject: "text",
     comments: "text"
   }
 )

  如果需要對所有欄位創建全文索引,則需要使用$xx標識

db.collection_name.createIndex( { "$**": "text" } )

  [註意]一個集合最多只能創建 一個 文本 索引

【使用】

  如果使用全文索引進行搜索,則需要使用如下格式

db.collection_name.find({$text:{$search: '...'}})

  假設使用如下的數據結構來存儲一個完整的文章,author存儲作者,title存儲標題,article存儲文章內容

{author:"",title:"",article:""}

  現在來添加一些數據,並對所有欄位創建全文索引

  下麵來搜索'huochai',可搜索到3條記錄

  如果搜索'a2',則只能搜索到第2條記錄

  如果搜索'a1 a2 a3',則相當於或的關係,a1 或 a2 或 a3,可以搜索到3條記錄

  如果搜索'huochai -css',相當於查找包含'huochai',但不包含'css'的記錄,包括第1和第3條

  如果要搜索且關係,比如同時包含huochai和css的記錄,則需要在內部添加引號," \"huochai\" \"css\" "

  [註意]只支持雙引號

【相似度】

  全文索引有一個相似度的概念,表示全文索引的搜索條件與記錄的內容有多麼相似

  在find()方法的第二個參數中,score是一個數字,該數字越大,表示相似度越高

db.collection_name.find({$text:{$search: '...'}},{score:{$meta:"textScore"}})

  現在,再插入一條內容,作者為'huochai'

  然後開始搜索'huochai',並帶有相似度

  下麵使用相似度排序,相似度高的排在前面

sort({score:{$meta:"textScore"}})

【限制】

  1、每次查詢,只能指定一個$text查詢

  2、$text查詢不能出現在$nor查詢中

  3、查詢中如果包含了$text,hint()將不再起作用

  4、只能對整個單詞查詢,不能對單詞的截取部分查詢。類似地,中文做全文查詢的時候,只能查詢一段話中有空格的該字或者詞

 

地理位置索引

  一般地,地理位置索引可以實現諸如按距離排序的餐館、在某區域內的店鋪篩選等

  可以將一些點的位置存儲在MongoDB中,創建地理位置索引索引後,可以按照位置來查找其他點。地理位置索引可以分為兩種:一種是2d索引,用於存儲和查找平面上的點;另一種是2dsphere索引,用於存儲和查找球面上的點

  查找方式一般有兩種:一種是查找距離某個點一定範圍內的點;另一種是查找包含在某區域內的點

【2D索引】

  2D索引的創建方式如下

db.<collection>.createIndex( { <location field> : "2d" , <additional field> : <value> } , { <index-specification options> } )

  options包括如下參數

{ min : <lower bound> , max : <upper bound> , bits : <bit precision> }

  在mongodb中使用經緯度表示位置,[經度, 緯度]。經度範圍在[-180,180],緯度範圍在[-90,90]

  [註意]預設邊界允許插入大於90或小於-90的不合理緯度值的文檔。而對於這樣不合理的點的地理查詢,資料庫行為是不可預知的。所以,儘量避免插入超出範圍的維度值

  2D索引的查詢方式有三種,包括$near$geoNear$geoWithin

  一種是使用$near查詢,即查詢距離某個點最近的點,預設返回100個

db.<collection>.find( { <location field> :{ $near : [ <x> , <y> ] } } )

  $maxDistance可以設置離當前點最遠的距離

  $minDistance可以設置離當前點最近的距離

  另一種是使用$geoNear查詢,$geoNear使用runCommand命令進行使用

db.runCommand({geoNear:<collection_name>,near:[x,y],minDistance:..,maxDistance:..,num:...})

  另一種是使用$geoWithin查詢,即查詢某個形狀內的點

  在mongodb中,有三種形狀,包括矩形、圓形和多邊形,使用方法如下

db.<collection>.find( { <location field> :{ $geoWithin :{ $box|$polygon|$center : <coordinates>} } } )

  第一種是矩形,使用$box表示

{$box:[[x1,y1],[x2,y2]]}

  第二種是圓形,使用$center表示

{$center:[[<x1>,<y1>],r]}

  第三種是多邊形,使用$polygon表示

{$polygon:[[<x1>,<y1>],[<x2>,<y2>],[<x3>,<y3>],...]}

【2dsphere索引】 

  2dsphere索引的創建方式如下

db.collection_name.createIndex({a:"2dsphere"})

  位置表示方式不再是簡單的經緯度,而是一種GeoJSON的表示方式,用來描述一個點、一條直線、多邊形等形狀,格式如下

{type:"",coordinates:[<coordinates>]}

 

 

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 轉自:http://blog.csdn.net/xiaoyusmile/article/details/5420252 1. 變數的定義、聲明 變數的聲明有兩種情況: 一種是需要建立存儲空間的。例如:int a。在聲明的時候就已經建立了存儲空間。這種聲明是"定義性聲明(defining declar ...
  • 自學到java的異常時,有一些自己的理解,現在總結一下。 1.為什麼要使用異常 剛開始估計很多初學者和我一樣,不理解為什麼要異常,什麼throws拋出異常,還要catch接住好麻煩的樣子,通過一個簡單的例子來理解一下。 這裡只是一個簡單的異常條件,園的半徑不可能小於等於0的,如果直接用if判斷然後處 ...
  • 前面我們分析了vector,這篇介紹STL中另一個重要的容器list list的設計 list由三部分構成:list節點、list迭代器、list本身 list節點 list是一個雙向鏈表,所以其list節點中有前後兩個指針。如下: list迭代器 前面我們說過vector是利用其記憶體分配類型成員給 ...
  • 原文鏈接:https://mp.weixin.qq.com/s?__biz=MzI0ODcxODk5OA==&mid=2247487055&idx=2&sn=ca0fe8740b78deb208c82eea73d56b37 誰會成為AI 和大數據時代的第一開發語言?這本已是一個不需要爭論的問題。如果 ...
  • 原文鏈接 http://www.envicloud.cn/pages/news/418.html 4 前段時間,ThoughtWorks在深圳舉辦一次社區活動上,有一個演講主題叫做“Fullstack JavaScript”,是關於用JavaScript進行前端、伺服器端,甚至資料庫(MongoDB ...
  • Python編程核心技術之正則表達式(regex) 一.正則表達式簡介 正則表達式(regex)為高級的文本模式匹配、抽取、與/或文本形式的搜索和替換功能提供了基礎。簡單的來說正則表達式是一些由字元和特殊符號組成的字元串,他們描述了模式的重覆或者表述多個字元,於是正則表達式能夠按照某種模式匹配一系列 ...
  • 1 概述 1 概述 本章敘述面向向對象設計的七大原則,七大原則分為:單一職責原則、開閉原則、里氏替換原則、依賴倒置原則、介面隔離原則、合成/聚合復用原則、迪米特法則。 2 七大OO面向對象設計 2 七大OO面向對象設計 2.1 單一職責原則SRP(Simple Responsibility Prin ...
  • 今天遇到一個坑,具體的不多說,直接上代碼 我預期的 arr 的結果應該是 最後arr的結果居然是這樣的 在一個基友群里問,最後終於自己得出結論了——這是因為值類型和引用類型不同的原因。 在JavaScript里的值大概分為兩種,一種是值類型,一種是引用類型。 值類型:數值、布爾值、null、unde ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...