標籤:一條直線 iter 使用 cond 幾分鐘 特定 索引值對 條件查詢 群組類型
索引通常能夠極大的提高查詢的效率,如果沒有索引,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 Descriptionbackground Boolean 建索引過程會阻塞其它資料庫操作,background可指定以後台方式建立索引,預設值為falseunique Boolean 建立的索引是否唯一。指定為true建立唯一索引。預設值為falsename string 索引的名稱。如果未指定,MongoDB通過串連索引的欄位名和排序次序產生一個索引名稱dropDups Boolean 在建立唯一索引時是否重複資料刪除記錄,指定 true 建立唯一索引。預設值為 falsesparse Boolean 對文檔中不存在的欄位資料不啟用索引;如果設定為true,索引欄位中不會查詢出不包含對應欄位的文檔。預設值為falsev 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>]}
MongoDB資料庫索引