MongoDB系列--輕松應對面試中遇到的MongonDB索引(index)問題
標簽: MongoDB 索引 MongoDB實戰 SpringBoot
??索引是特殊的數據結構,索引存儲在一個易于遍歷讀取的數據集合中( 索引存儲在特定字段或字段集的值),而且是使用了B-tree結構。索引可以極大程度提升MongoDB查詢效率。
??如果沒有索引,MongoDB必須執行全集合collections掃描,即掃描集合中的每個文檔,選取符合查詢條件的文檔document。 如果查詢時存在適當的索引,MongoDB可以使用索引來限制它必須查詢的文檔document的數量,特別是在處理大量數據時,所以選擇正確的索引是很關鍵的、重要的。
創建索引,需要考慮的問題:
- 每個索引至少需要數據空間為8kb;
- 添加索引會對寫入操作會產生一些性能影響。 對于具有高寫入率的集合Collections,索引很昂貴,因為每個插入也必須更新任何索引;
- 索引對于具有高讀取率的集合Collections很有利,不會影響沒索引查詢;
- 處于索引處于action狀態時,每個索引都會占用磁盤空間和內存,因此需要對這種情況進行跟蹤檢測。
索引限制:
- 索引名稱長度不能超過128字段;
- 復合索引不能超過32個屬性;
- 每個集合Collection不能超過64個索引;
- 不同類型索引還具有各自的限制條件。
1. 索引管理
1.1 索引創建
索引創建使用createIndex()方法,格式如下:
db.collection.createIndex(<key and index type specification>,<options>)
createIndex() 接收可選參數,可選參數列表如下:
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引過程會阻塞其它數據庫操作,background可指定以后臺方式創建索引,即增加 “background” 可選參數。 “background” 默認值為false。 |
unique | Boolean | 建立的索引是否唯一。指定為true創建唯一索引。默認值為false. |
name | string | 索引的名稱。如果未指定,MongoDB的通過連接索引的字段名和排序順序生成一個索引名稱。 |
dropDups | Boolean | 3.0+版本已廢棄。在建立唯一索引時是否刪除重復記錄,指定 true 創建唯一索引。默認值為 false. |
sparse | Boolean | 對文檔中不存在的字段數據不啟用索引;這個參數需要特別注意,如果設置為true的話,在索引字段中不會查詢出不包含對應字段的文檔.。默認值為 false. |
expireAfterSeconds | integer | 指定一個以秒為單位的數值,完成 TTL設定,設定集合的生存時間。 |
v | index version | 索引的版本號。默認的索引版本取決于mongod創建索引時運行的版本。 |
weights | document | 索引權重值,數值在 1 到 99,999 之間,表示該索引相對于其他索引字段的得分權重。 |
default_language | string | 對于文本索引,該參數決定了停用詞及詞干和詞器的規則的列表。 默認為英語 |
language_override | string | 對于文本索引,該參數指定了包含在文檔中的字段名,語言覆蓋默認的language,默認值為 language. |
1.2 查看索引
查看Collection中所有索引,格式如下:
db.collection.getIndexes()
1.3 刪除索引
刪除Collection中的索引:格式如下:
db.collection.dropIndexes() //刪除所有索引
db.collection.dropIndex() //刪除指定的索引
1.4 索引名稱
索引的默認名稱是索引鍵和索引中每個鍵的value1或-1,形式index_name+1/-1,比如:
db.products.createIndex( { item: 1, quantity: -1 } )----索引名稱為item_1_quantity_-1
也可以指定索引名稱:
db.products.createIndex( { item: 1, quantity: -1 } , { name: "inventory" } ) ----索引名稱為inventory
1.5 查看索引創建過程以及終止索引創建
方法 | 解析 |
---|---|
db.currentOp() | 查看索引創建過程 |
db.killOp(opid) | 終止索引創建,其中-opid為操作id |
1.6 索引使用情況
形式 | 解析 |
---|---|
$indexStats | 獲取索引訪問信息 |
explain() | 返回查詢情況:在executionStats模式下使用db.collection.explain()或cursor.explain()方法返回有關查詢過程的統計信息,包括使用的索引,掃描的文檔數以及查詢處理的時間(以毫秒為單位)。 |
Hint() | 控制索引,例如要強制MongoDB使用特定索引進行db.collection.find()操作,請使用hint()方法指定索引 |
1.7 MongoDB度量標準
MongoDB提供了許多索引使用和操作的度量標準,在分析數據庫的索引使用時可能需要考慮這些度量標準,如下所示:
形式 | 解析 |
---|---|
metrics.queryExecutor.scanned | 在查詢和查詢計劃評估期間掃描的索引項的總數 |
metrics.operation.scanAndOrder | 返回無法使用索引執行排序操作的已排序數字的查詢總數 |
collStats.totalIndexSize | 所有索引的總大小。 scale參數會影響此值。如果索引使用前綴壓縮(這是WiredTiger的默認值),則返回的大小將反映計算總計時任何此類索引的壓縮大小。 |
collStats.indexSizes | 指定集合collection上每個現有索引的鍵和大小。 scale參數會影響此值 |
dbStats.indexes | 包含數據庫中所有集合的索引總數的計數。 |
dbStats.indexSize | 在此數據庫上創建的所有索引的總大小 |
1.8 后臺索引操作
??在密集(快達到數據庫最大容量)Collection創建索引:在默認情況下,在密集的Collection(快達到數據庫最大容量)時創建索引,會阻止其他操作。在給密集的Collection(快達到數據庫最大容量)創建索引時,
索引構建完成之前,保存Collection的數據庫不可用于讀取或寫入操作。 任何需要對所有數據庫(例如listDatabases)進行讀或寫鎖定的操作都將等待不是后臺進程的索引構建完成。
因此可以使用background屬性進行設置后臺索引創建,操作如下:
db.people.createIndex( { zipcode: 1 }, { background: true } )
默認情況下,在創建索引時,background為false,可以和其他屬性進行組合使用:
db.people.createIndex( { zipcode: 1 }, { background: true, sparse: true } )
2. 索引類型
2.1 單字段索引(Single Field Indexes)
??MongoDB可以在任何一個字段中創建索引,默認情況下,所有的集合(collections)會在_id字段中創建索引。_id索引是為防止客戶端插入具有相同value的_id字段的文檔Document,而且不能刪除_id字段索引。
??在分片群集中使用_id索引,如果不使用_id字段作為分片鍵,則應用程序必須確保_id字段中值的唯一性以防止出錯,解決方法為使用標準的自動生成的ObjectId來完成。
??一般單字段索引的value中,“1”指定按升序對項目進行排序的索引,“-1”指定按降序對項目進行排序的索引。如下所示:
在單個字段創建索引,示例如下:
{
"_id": ObjectId("570c04a4ad233577f97dc459"),
"score": 1034,
"location": { state: "NY", city: "New York" }
}
//創建單字段索引
db.records.createIndex( { score: 1 } )
//支持的查詢
db.records.find( { score: 2 } )
db.records.find( { score: { $gt: 10 } } )
在嵌入式文檔Document中的字段創建索引,示例如下:
db.records.createIndex( { "location.state": 1 } )
//支持的查詢
db.records.find( { "location.state": "CA" } )
db.records.find( { "location.city": "Albany", "location.state": "NY" } )
在嵌入式文檔Document創建索引,示例如下:
db.records.createIndex( { location: 1 } )
//支持查詢
db.records.find( { location: { city: "New York", state: "NY" } } )
2.2 復合索引(Compound Index)
復合索引指的是將多個key組合到一起創建索引,這樣可以加速匹配多個鍵的查詢。特性如下:
- MongoDB對任何復合索引都限制了32個字段;
- 無法創建具有散列索引(hash index)類型的復合索引。如果嘗試創建包含散列索引字段的復合索引,則會報錯;
- 復合索引創建字段索引的順序是很重要的。因為索引以升序(1)或降序(-1)排序順序存儲對字段的引用; 對于單字段索引,鍵的排序順序無關緊要,因為MongoDB可以在任一方向上遍歷索引。 但是,對于復合索引,排序順序可以決定索引是否可以支持排序操作;
- 除了支持在所有索引字段上匹配的查詢之外,復合索引還可以支持與索引字段的前綴匹配的查詢。
創建復合索引的格式:
db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } )
排序順序,兩個字段的復合索引示例,index{userid:1,score:-1},先userid的value排序,然后再userid排序基礎下進行score排序。如下圖:
創建復合索引,示例如下:
{
"_id": ObjectId(...),
"item": "Banana",
"category": ["food", "produce", "grocery"],
"location": "4th Street Store",
"stock": 4,
"type": "cases"
}
//創建復合索引
db.products.createIndex( { "item": 1, "stock": 1 } )
//支持的查詢
db.products.find( { item: "Banana" } )
db.products.find( { item: "Banana", stock: { $gt: 5 } } )
復合索引中的前綴查詢,示例如下:
//創建復合索引
db.products.createIndex({ "item": 1, "location": 1, "stock": 1 })
//前綴為:{ item: 1 }與{ item: 1, location: 1 }
//支持前綴查詢為
db.products.find( { item: "Banana" } )
db.products.find( { item: "Banana", location: “beijing”} )
//不支持前綴查詢,不會提高查詢效率
//不包含前綴字段
db.products.find( { location: “beijing”} )
db.products.find( { stock: { $gt: 5 } )
db.products.find( { location: “beijing”,stock: { $gt: 5 } )
//不按照創建復合索引字段順序的前綴查詢
db.products.find( { location: “beijing”,item: "Banana" },stock: { $gt: 5 } )
2.3 多鍵索引
??MongoDB使用多鍵索引為數組的每個元素都創建索引,多鍵索引可以建立在字符串、數字等key或者內嵌文檔(document)的數組上,如果索引字段包含數組值,MongoDB會自動確定是否創建多鍵索引; 您不需要手動指定多鍵類型。 其中創建方式:
db.coll.createIndex( { <field>: < 1 or -1 > } )
索引邊界
??使用多鍵索引,會出現索引邊界(索引邊界即是查詢過程中索引能查找的范圍)的計算,并計算必須遵循一些規則。即當多個查詢的條件中字段都存在索引中時,MongoDB將會使用交集或者并集等來判斷這些條件索引字段的邊界最終產生一個最小的查找范圍。可以分情況:
1).交集邊界
??交集邊界即為多個邊界的邏輯交集,對于給定的數組字段,假定一個查詢使用了數組的多個條件字段并且可以使用多鍵索引。如果使用了$elemMatch連接了條件字段,則MongoDB將會相交多鍵索引邊界,示例如下:
//survey Collection中document有一個item字段和一個ratings數組字段
{ _id: 1, item: "ABC", ratings: [ 2, 9 ] }
{ _id: 2, item: "XYZ", ratings: [ 4, 3 ] }
//在ratings數組上創建多鍵索引:
db.survey.createIndex({ratings:1})
//兩種查詢
db.survey.find({ratings:{$elemMatch:{$gte:3,$lte:6}}}) //(1)
db.survey.find( { ratings : { $gte: 3, $lte: 6 } } ) //(2)
??查詢條件分別為大于等于3、小于等于6,其中 (1)中使用了$elemMatch連接查詢條件,會產生一個交集ratings:[[3,6]。在(2)查詢中,沒使用$elemMatch,則不會產生交集,只要滿足任何一個條件即可。
2).并集邊界
??并集邊界常常用在確定多鍵組合索引的邊界,例如:給定的組合索引{a:1,b:1},在字段a上有一個邊界:[3,+∞),在字段b上有一個邊界:(-∞,6],相并這兩個邊界的結果是:{ a: [ [ 3, Infinity ] ], b: [ [ -Infinity, 6 ] ] }。
??而且如果MongoDB沒法并集這兩個邊界,MongoDB將會強制使用索引的第一個字段的邊界來進行索引掃描,在這種情況下就是: a: [ [ 3, Infinity ] ]。
3、數組字段的組合索引
??一個組合索引的索引字段是數組,例如一個survey collection集合document文檔中含有item字段和ratings數組字段,示例如下:
{ _id: 1, item: "ABC", ratings: [ 2, 9 ] }
{ _id: 2, item: "XYZ", ratings: [ 4, 3 ] }
//在item字段和ratings字段創建一個組合索引:
db.survey.createIndex( { item: 1, ratings: 1 } )
//查詢條件索引包含的兩個key
db.survey.find( { item: "XYZ", ratings: { $gte: 3 } } )
分別處理查詢條件:
item: "XYZ" --> [ [ "XYZ", "XYZ" ] ];
ratings: { $gte: 3 } --> [ [ 3, Infinity ] ].
MongoDB使用并集邊界來組合這兩個邊界:
{ item: [ [ "XYZ", "XYZ" ] ], ratings: [ [ 3, Infinity ] ] }
4).內嵌文檔document的數組上建立組合索引
??如果數組中包含內嵌文檔document,想在包含的內嵌文檔document字段上建立索引,需要在索引聲明中使用逗號“,” 來分隔字段名,示例如下:
ratings: [ { score: 2, by: "mn" }, { score: 9, by: "anon" } ]
則score字段名稱就是:ratings.score。
5).混合不是數組類型的字段和數組類型字段的并集
{ _id: 1, item: "ABC", ratings: [ { score: 2, by: "mn" }, { score: 9, by: "anon" } ] }
{ _id: 2, item: "XYZ", ratings: [ { score: 5, by: "anon" }, { score: 7, by: "wv" } ] }
//在item和數組字段ratings.score和ratings.by上創建一個組合索引
db.survey2.createIndex( { "item": 1, "ratings.score": 1, "ratings.by": 1 } )
//查詢
db.survey2.find( { item: "XYZ", "ratings.score": { $lte: 5 }, "ratings.by": "anon" } )
分別對查詢條件進行處理:
item: "XYZ"--> [ ["XYZ","XYZ"] ];
score: {$lte:5}--> [[-Infinity,5]];
by: "anon" -->["anon","anon"].
??MongoDB可以組合 item鍵的邊界與 ratings.score和ratings.by兩個邊界中的一個,到底是score還是by索引邊界這取決于查詢條件和索引鍵的值。MongoDB不能確保哪個邊界和item字段進行并集。
但如果想組合ratings.score和ratings.by邊界,則查詢必須使用$elemMatch。
6).數組字段索引的并集邊界
??在數組內部并集索引鍵的邊界,
- 除了字段名稱外,索引鍵必須有相同的字段路徑,
- 查詢的時候必須在路徑上使用$elemMatch進行聲明
- 對于內嵌的文檔,使用逗號分隔的路徑,比如a.b.c.d是字段d的路徑。為了在相同的數組上并集索引鍵的邊界,需要$elemMatch必須使用在a.b.c的路徑上。
比如:在ratings.score和ratings.by字段上創建組合索引:
db.survey2.createIndex( { "ratings.score": 1, "ratings.by": 1 } )
字段ratings.score和ratings.by擁有共同的路徑ratings。下面的查詢使用$elemMatch則要求ratings字段必須包含一個元素匹配這兩個條件:
db.survey2.find( { ratings: { $elemMatch: { score: { $lte: 5 }, by: "anon" } } } )
分別對查詢條件進行處理:
score: { $lte: 5 } --> [ -Infinity, 5 ];
by: "anon"--> [ "anon", "anon" ].
MongoDB可以使用并集邊界來組合這兩個邊界:
{ "ratings.score" : [ [ -Infinity, 5 ] ], "ratings.by" : [ [ "anon", "anon" ] ] }
7). 還有不使用$elemMatch進行查詢以及不完整的路徑上使用$elemMatch,想要了解更多可以查看《官方文檔-Multikey Index Bounds》。
限制:
- 對于一個組合多鍵索引,每個索引文檔最多只能有一個索引字段的值是數組。如果組合多鍵索引已經存在了,不能在插入文檔的時候違反這個限制;
- 不能聲明一個多鍵索引作為分片鍵索引;
- 哈希索引不能擁有多鍵索引;
- 多鍵索引不能進行覆蓋查詢;
- 當一個查詢聲明把數組整體作為精確匹配的時候,MongoDB可以使用多鍵索引來查找這個查詢數組的第一個元素,但是不能使用多鍵索引掃描來找出整個數組。代替方案是當使用多鍵索引查詢出數組的第一個元素之后,MongoDB再對過濾之后的文檔再進行一次數組匹配。
2.4 全文索引(text index)
??MongoDB提供了一種全文索引類型,支持在Collection中搜索字符串內容,對字符串與字符串數組創建全文可搜索的索引
。 這些全文索引不存儲特定于語言的停用詞(例如“the”,“a”,“或”),并且阻止document集合中的單詞僅存儲根詞。創建方式如下:
db.collection.createIndex( { key: "text",key:"text" ..... } )
而且MongoDB提供權重以及通配符的創建方式。查詢方式多個字符串空格隔開,排除查詢使用“-”如下所示:
db.collection.find({$text:{$search:"runoob add -cc"}})
要刪除全本索引,需要將索引的名稱傳遞給db.collection.dropIndex()方法, 而要獲取索引的名稱,使用db.collection.getIndexes()方法。
??還可以指定全文索引的語言,通過default_language屬性 在創建時指定, 或者使用language_override屬性 覆蓋掉創建document文檔時默認的語言,如下所示:
//指定不同的語言的方法:創建全文索引的時候使用default_language屬性
db.collection.createIndex(
{ content : "text" },
{ default_language: "spanish" })
//使用language_override屬性覆蓋默認的語言
db.quotes.createIndex( { quote : "text" },
{ language_override: "idioma" } )
//默認的全文索引名稱為context_text,users.comments.text,指定名稱MyTextIndex
db.collection.createIndex(
{
content: "text",
"users.comments": "text",
"users.profiles": "text"
},
{
name: "MyTextIndex"
}
)
權重
??每個全文索引可以通過設置權重來分配不同的搜索程度,默認權重為1,對于文檔中的每個索引字段,MongoDB將匹配數乘以權重并將結果相加。 使用此總和,MongoDB然后計算文檔的分數,示例如下:
{
_id: 1,
content: "This morning I had a cup of coffee.",
about: "beverage",
keywords: [ "coffee" ]
}
{
_id: 2,
content: "Who doesn't like cake?",
about: "food",
keywords: [ "cake", "food", "dessert" ]
}
//通過db.blog.createIndex來指定weight權重
db.blog.createIndex(
{
content: "text",
keywords: "text",
about: "text"
},
{
weights: {
content: 10,
keywords: 5
},
name: "TextIndex"
}
)
content權重為10,keywords為5,about為默認權重1,因此可以得出content對于keywords查詢頻率高于2倍,而對于about字段則是10倍。
通配符全文索引
??在多個字段上創建全文索引時,還可以使用通配符說明符($**)。 使用通配符全文索引,MongoDB會為包含Collection中每個Document的字符串數據。例如:
db.collection.createIndex( { "$**": "text" } )
通配符全本索引是多個字段上的全本索引。 因此,可以在創建索引期間為特定字段指定權重,以控制結果的排名。
限制
- 每個Collection一個全文索引:一個collection最多只有一個全文索引,
- Text Search 和Hints函數,如果查詢包含$ text查詢表達式,則不能使用hint();
- Text Index and Sort,排序操作無法從文本索引獲取排序順序,即使是復合文本索引也是如此; 即排序操作不能使用文本索引中的排序;
- 復合索引:復合索引可以包括文本索引鍵與升序/降序索引鍵的組合。 但是,這些復合索引具有以下限制:
1).復合文本索引不能包含任何其他特殊索引類型,例如多鍵或地理空間索引字段。
2).如果復合文本索引包括文本索引鍵之前的鍵,則執行$ text搜索時,查詢謂詞必須包含前面鍵上的相等匹配條件。
3).創建復合文本索引時,必須在索引規范文檔中相鄰地列出所有文本索引鍵。
2.5 Hash 索引
??散列索引使用散列函數來計算索引字段值的散列值。 散列函數會折疊嵌入的文檔并計算整個值的散列值,但不支持多鍵(即數組)索引。
生成hash索引key使用了convertShardKeyToHashed()方法。創建方式如下:
db.collection.createIndex( { _id: "hashed" } )
而且散列索引支持使用散列分片鍵進行分片。 基于散列的分片使用字段的散列索引作為分片鍵來分割整個分片群集中的數據。
3. 索引屬性
索引屬性有TTL索引、惟一性索引、部分索引、稀疏索引以及區分大小寫索引。
3.1 TTL索引(TTL Indexes)
??TTL索引是特殊的單字段索引,并且字段類型必須是date類型或者包含有date類型的數組,MongoDB可以使用它在一定時間后或在特定時鐘時間自動從集合中刪除文檔。 數據到期對于某些類型的信息非常有用,例如機器生成的事件數據,日志和會話信息,這些信息只需要在數據庫中持續有限的時間。
創建TTL索引方法,和普通索引的創建方法一樣,只是會多加一個expireAfterSeconds的屬性,格式如下:
db.collection.createIndex( {key and index type specification},{ expireAfterSeconds: time})
例子:
db.eventlog.createIndex( { "lastModifiedDate": 1 }, { expireAfterSeconds: 3600 } )
指定過期時間
首先在保存BSON日期類型值或BSON日期類型對象數組的字段上創建TTL索引,并指定expireAfterSeconds值為0.對于集合中的每個文檔,設置 索引日期字段為與文檔到期時間對應的值。示例操作如下:
第一步:
db.log_events.createIndex( { "expireAt": 1 }, { expireAfterSeconds: 0 } )
第二步:
db.log_events.insert( {
"expireAt": new Date('July 22, 2013 14:00:00'),
"logEvent": 2,
"logMessage": "Success!"
} )
數據過期類型:
- 當指定時間到了過期的閾值數據就會過期并刪除;
- 如果字段是數組,并且索引中有多個日期值,MongoDB使用數組中最低(即最早)的日期值來計算到期閾值;
- 如果文檔(document)中的索引字段不是日期或包含日期值的數組,則文檔(document)將不會過期;
- 如果文檔(document)不包含索引字段,則文檔(document)不會過期。
TTL索引特有限制:
- TTL索引是單字段索引。 復合索引不支持TTL并忽略expireAfterSeconds選項;
- _id屬性不支持TTL索引;
- 無法在上限集合上創建TTL索引,因為MongoDB無法從上限集合中刪除文檔;
- 不能使用createIndex()方法來更改現有索引的expireAfterSeconds值。而是將collMod數據庫命令與索引集合標志結合使用。 否則,要更改現有索引的選項的值,必須先刪除索引并重新創建;
- 如果字段已存在非TTL單字段索引,則無法在同一字段上創建TTL索引,因為無法在相同key創建不同類型的的索引。 要將非TTL單字段索引更改為TTL索引,必須先刪除索引并使用expireAfterSeconds選項重新創建。
3.2 惟一性索引(Unique Indexes)
??唯一索引可確保索引字段不存儲重復值; 即強制索引字段的唯一性。 默認情況下,MongoDB在創建集合期間在_id字段上創建唯一索引。創建方式如下:
db.collection.createIndex( <key and index type specification>, { unique: true } )
單個字段創建方式,示例如下:
db.members.createIndex( { "user_id": 1 }, { unique: true } )
唯一性復合索引: 還可以對復合索引強制執行唯一約束。 如果對復合索引使用唯一約束,則MongoDB將對索引鍵值的組合強制實施唯一性。示例如下:
//創建的索引且強制groupNumber,lastname和firstname值組合的唯一性。
db.members.createIndex( { groupNumber: 1, lastname: 1, firstname: 1 }, { unique: true } )
唯一多鍵索引:
{ _id: 1, a: [ { loc: "A", qty: 5 }, { qty: 10 } ] }
//創建索引:
db.collection.createIndex( { "a.loc": 1, "a.qty": 1 }, { unique: true } )
//插入數據:唯一索引允許將以下Document插入Collection中,因為索引強制執行a.loc和a.qty值組合的唯一性:
db.collection.insert( { _id: 2, a: [ { loc: "A" }, { qty: 5 } ] } )
db.collection.insert( { _id: 3, a: [ { loc: "A", qty: 10 } ] } )
創建唯一索引到副本或者分片中:
對于副本集和分片集群,使用滾動過程創建唯一索引需要在過程中停止對集合的所有寫入。 如果在過程中無法停止對集合的所有寫入,請不要使用滾動過程。 相反,通過以下方式在集合上構建唯一索引:
- 在主服務器上為副本集發出db.collection.createIndex()
- 在mongos上為分片群集發出db.collection.createIndex()
NOTE:詳細解析可以看
限制:
- 如果集合已經包含超出索引的唯一約束的數據(即有重復數據),則MongoDB無法在指定的索引字段上創建唯一索引。
- 不能在hash索引上創建唯一索引
- 唯一約束適用于Collection中的一個Document。由于約束適用于單文檔document,因此對于唯一的多鍵索引,只要該文檔document的索引鍵值不與另一個文檔document的索引鍵值重復,文檔就可能具有導致重復索引鍵值的數組元素。 在這種情況下,重復索引記錄僅插入索引一次。
- 分片Collection唯一索引只能如下:
1).分片鍵上的索引
2).分片鍵是前綴的復合索引
3). 默認的_id索引; 但是,如果_id字段不是分片鍵或分片鍵的前綴,則_id索引僅對每個分片強制執行唯一性約束。如果_id字段不是分片鍵,也不是分片鍵的前綴,MongoDB希望應用程序在分片中強制執行_id值的唯一性。
3.3 部分索引(Partial Indexes)
??部分索引通過指定的過濾表達式去達到局部搜索。通過db.collection.createIndex()方法中增加partialFilterExpression屬性創建,過濾表達式如下:
- 等式表達式(即 file:value或使用$eq運算符)
- $exists表達式
- $gt,$gte,$lt,$lte 表達式
- $type表達式
- $and
示例如下:
//創建部分索引
db.restaurants.createIndex(
{ cuisine: 1, name: 1 },
{ partialFilterExpression: { rating: { $gt: 5 } } }
)
//查詢情況分類
db.restaurants.find( { cuisine: "Italian", rating: { $gte: 8 } } ) //(1)
db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } ) //(2)
db.restaurants.find( { cuisine: "Italian" } ) //(3)
其中:
- (1)查詢: 查詢條件{ $gte: 8 }于創建索引條件{ $gt: 5 }可以構成一個完整集(查詢條件是創建索引條件的子集,即大于5可以包含大于等于 8),可以使用部分索引查詢。
- (2)查詢: 條件達不到完整集,MongoDB將不會將部分索引用于查詢或排序操作。
- (3)查詢: 次查詢沒有使用過濾表達式,也不會使用部分索引,因為要使用部分索引,查詢必須包含過濾器表達式(或指定過濾器表達式子集的已修改過濾器表達式)作為其查詢條件的一部分
限制:
- 不可以僅通過過濾表達式創建多個局部索引;
- 不可以同時使用局部索引和稀疏索引(sparse index);
- _id索引不能使用局部索引,分片索引(shard key index)也不能使用局部索引;
- 同時指定partialFilterExpression和唯一約束,則唯一約束僅適用于滿足過濾器表達式的文檔。 如果Document不符合篩選條件,則具有唯一約束的部分索引是允許插入不符合唯一約束的Document。
3.4 稀疏索引(Sparse Indexes)
??稀疏索只引搜索包含有索引字段的文檔的條目,跳過索引鍵不存在的文檔,即稀疏索引不會搜索不包含稀疏索引的文檔。默認情況下, 2dsphere (version 2), 2d, geoHaystack, 全文索引等總是稀疏索引。創建方式db.collection.createIndex()方法增加sparse屬性,如下所示:
db.addresses.createIndex( { "xmpp_id": 1 }, { sparse: true } )
稀疏索引不被使用的情況: 如果稀疏索引會導致查詢和排序操作的結果集不完整,MongoDB將不會使用該索引,除非hint()示顯式指定索引。
稀疏復合索引:
- 對于包含上升/下降排序的稀疏復合索引,只要復合索引中的一個key 索引存在都會被檢測出來
- 對于包含上升/下降排序的包含地理空間可以的稀疏復合索引,只有存在地理空間key才能被檢測出來
- 對于包含上升/下降排序的全文索引的稀疏復合索引,只有存在全文索引索引才可以被檢測
稀疏索引與唯一性: 一個既包含稀疏又包含唯一的索引避免集合上存在一些重復值得文檔,但是允許多個文檔忽略該鍵。滿足稀疏索引和唯一性操作其兩個限制都要遵循。
整合示例如下:
{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
//在score中創建稀疏索引:
db.scores.createIndex( { score: 1 } , { sparse: true } )
//查詢
db.scores.find( { score: { $lt: 90 } } ) //(1)
db.scores.find().sort( { score: -1 } ) //(2)
db.scores.find().sort( { score: -1 } ).hint( { score: 1 } ) //(3)
//在score字段上創建具有唯一約束和稀疏過濾器的索引:
db.scores.createIndex( { score: 1 } , { sparse: true, unique: true } )
//該索引允許插入具有score字段的唯一值的文檔或不包括得分字段的文檔。如下:
db.scores.insert( { "userid": "AAAAAAA", "score": 43 } )
db.scores.insert( { "userid": "BBBBBBB", "score": 34 } )
db.scores.insert( { "userid": "CCCCCCC" } )
db.scores.insert( { "userid": "DDDDDDD" } )
//索引不允許添加以下文檔,因為已存在score值為82和90的文檔
db.scores.insert( { "userid": "AAAAAAA", "score": 82 } )
db.scores.insert( { "userid": "BBBBBBB", "score": 90 } )
其中:
- (1)查詢: 可以使用稀疏索引查詢,返回完整集:{ “_id” : ObjectId(“523b6e61fb408eea0eec2648”), “userid” : “abby”, “score” : 82 }
- (2)查詢: 即使排序是通過索引字段進行的,MongoDB也不會選擇稀疏索引來完成查詢以返回完整的結果:
{ “_id” : ObjectId(“523b6e6ffb408eea0eec2649”), “userid” : “nina”, “score” : 90 }
{ “_id” : ObjectId(“523b6e61fb408eea0eec2648”), “userid” : “abby”, “score” : 82 }
{ “_id” : ObjectId(“523b6e32fb408eea0eec2647”), “userid” : “newbie” } - (3)查詢: 使用hint()返回所需完整集:
{ “_id” : ObjectId(“523b6e6ffb408eea0eec2649”), “userid” : “nina”, “score” : 90 }
{ “_id” : ObjectId(“523b6e61fb408eea0eec2648”), “userid” : “abby”, “score” : 82 }
4. 其他事項
4.1 索引策略
索引策略:
- 應用程序的最佳索引必須考慮許多因素,包括期望查詢的類型,讀取與寫入的比率以及系統上的可用內存量。
- 在開發索引策略時,您應該深入了解應用程序的查詢。在構建索引之前,映射將要運行的查詢類型,以便您可以構建引用這些字段的索引。索引具有性能成本,但是對于大型數據集上的頻繁查詢而言,它們的價值更高。考慮應用程序中每個查詢的相對頻率以及查詢是否證明索引是合理的。
- 設計索引的最佳總體策略是使用與您將在生產中運行的數據集類似的數據集來分析各種索引配置,以查看哪些配置性能最佳。檢查為集合創建的當前索引,以確保它們支持您當前和計劃的查詢。如果不再使用索引,請刪除索引。
- 通常,MongoDB僅使用一個索引來完成大多數查詢。但是,$或查詢的每個子句可能使用不同的索引,從2.6開始,MongoDB可以使用多個索引的交集。
4.2 后續
??后續還會有MongonDB索引優化,副本集以及分片總結、最重要還會總結在使用MongoDB實戰以及實戰過程出現的一些坑,可關注后續更新MongoDB系列。
智能推薦
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
猜你喜歡
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...
19.vue中封裝echarts組件
19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...