Index
定義
索引,一個單獨的、存儲在磁盤上的數據結構
mongodb 的索引采用 B-tree 數據結構存儲
-
易於遍歷,支持相等匹配和范圍查詢
-
存儲字段的值以及指向其所在文檔的指針
包含集合中所有文檔的指針(包含數據表中所有記錄的引用指針)
-
按字段的值排序
mongodb index
- 在集合級別定義索引,支持在文檔中的任何字段或子字段上建立索引
- 給某個字段添加索引,可以快速找出在該字段有特定值的文檔,提高查詢速度
- 如果沒有索引,mongodb必須掃描集合中所有的文檔,以選擇那些符合查詢條件的文檔。一般而言,在查詢文檔時應避免掃描全部文檔,這樣會使查詢速度非常慢
- 建立索引可以縮小mongodb掃描文檔的數量,提高查詢速度
- mongodb 可以返回基於索引排序的查詢結果
演示基於索引查詢並排序
_id
- mongodb 默認會為文檔創建一個
_id
字段,並建立唯一索引 - 不能刪除建立在
_id
字段上的索引 - 索引名稱為
_id_
創建索引
db.collection.createIndex
-
為集合創建索引
-
如果索引(名稱)已經存在,則不會再次創建
-
除 collation 選項外,使用 不同的選項 不會創建 具有相同索引規范的 索引,也不會修改這些選項的值
只能刪除之前的索引,重新使用新的選項創建
-
使用不同的 collation 選項,可以創建 多個 具有相同的索引規范的 索引,但是需要指定 唯一的 索引名稱
db.person.createIndex({name:1},{name:"a_c", collation:{locale:"fr"}}) db.person.createIndex({name:1},{name:"a_b", collation:{locale:"fa"}})
-
如果文檔不包含指定的字段,則操作失敗
格式
db.collection.createIndex(keys, options)
-
keys
- 類型:Document
- 描述:
-
包含字段和值的文檔,其中字段是索引鍵,值是該字段的索引類型
判斷索引是否相同根據索引的 keys,因此 keys 不同就代表索引不同
-
用下划線連接組成默認索引名稱
-
同一個字段上只能創建一個相同類型的索引,可以創建多個不同類型的索引
例如 {age:1} {age:-1} 兩個keys不同,索引(名)不同
-
-
索引類型包括:test、geospatial、hashed、ascending、descending
排序規則
- 值為 1,表示升序(ascending)
- 值為 -1,表示降序(descending)
-
-
options
-
類型:Document
-
描述:創建索引的選項,不同類型的索引有特定於該類型的選項,以下為共有選項
-
background
-
類型:布爾【4.2版本中被廢棄】
-
描述:是否在后台執行創建索引的過程,不阻塞對集合的操作
-
false【默認】
不在后台創建
-
true
后台創建
-
-
4.2 版本中所有的索引構建,使用一個優化的構建過程,它只在構建過程的開始和結束時持有獨占鎖,構建過程中讓步於讀寫操作
4.2 版本會忽略該選項
-
4.2 版本之前索引的構建的整個過程都會持有獨占鎖,阻塞數據庫及其所有集合上的操作,直到操作完成,在后台創建索引不會持有獨占鎖
-
-
unique
-
類型:布爾
-
描述:
-
是否創建具有唯一性的索引
-
true
此索引具有唯一性,當索引重復時,不接受對文檔的插入或更新
-
false【默認】
-
-
不適用於 hashed 索引
-
-
-
name
-
類型:字符串
-
描述
-
自定義索引名稱
-
如果不指定,mongodb將通過 下划線 連接 索引字段的名稱和排序規則 生成一個索引名稱
例如在 { item : 1, quantity: -1 } 上創建的索引名稱為 item_1_quantity_-1
-
一旦創建不能修改,只能刪除再重新創建
-
4.2 版本之前,索引名最大長度為 127 字節,4.2版本開始取消該限制
-
-
partialFilterExpression
-
類型:Document
-
描述:僅為集合中符合條件的文檔建立索引,降低創建和維護成本
-
-
sparse
[spɑrs] 稀疏
-
類型:布爾
-
描述:僅為集合中具有指定字段的文檔建立索引
-
true
建立稀疏索引
-
false 【默認】
zdsphere、2d、geoHaystack、text 默認為稀疏文檔,忽略此選項
-
-
-
expireAfterSeconds
- 類型:integer,單位 秒
- 描述:用於 TTL 索引中 控制 文檔保存在集合中的時間
-
storageEngine
- 類型:Document
- 描述:指定存儲引擎配置
-
-
Returns
-
成功
{ "createdCollectionAutomatically" : false, "numIndexesBefore" : 3, "numIndexesAfter" : 4, "ok" : 1 }
- createdCollectionAutomatically 是否自動創建集合
- numIndexesBefore 創建之前索引個數
- numIndexesAfter 創建之后索引個數
- ok:1 創建成功
-
失敗
{ "ok" : 0, "errmsg" : "Error: hashed indexes do not currently support array values", "code" : 16766, "codeName" : "Location16766" }
- ok:0 創建失敗
- errmsg 失敗信息
- code 失敗碼
- codeName ?
查詢索引
db.collection.getIndexes
-
查詢集合中所有的索引信息
-
返回一個數組,數組元素是描述索引信息的文檔
索引信息包括創建索引時的信息:keys 以及 options
格式
db.collection.getIndexes()
db.collection.totalIndexSize
- 查詢集合中所有索引的大小
- 如果索引使用前綴壓縮 (這是WiredTiger的默認值),則返回壓縮后的大小
- 單位 字節 byte
格式
db.collection.totalIndexSize()
刪除索引
db.collection.dropIndex
- 刪除指定索引
- 不能刪除默認創建在
_id
字段上的索引
格式
db.collection.dropIndex(index)
-
index
-
類型:字符串、文檔
-
描述:指定要刪除的索引
-
可以指定索引的名稱 或 索引規范文檔
通過
db.collection.getIndexes()
獲取索引名稱 -
刪除 text 類型的索引,必須指定索引名稱
無法通過索引規范文檔找到索引,刪除失敗
-
4.2 版本開始,不能通過
db.collection.dropIndex("*")
刪除所有非_id
字段上的索引,應該使用db.collection.dropIndexes()
-
-
排它鎖
- 4.2 版本之前,dropIndex 操作在父級數據庫上獲取一個排它鎖,阻塞所有對數據庫及其所有集合的操作,直到操作完成
- 4.2 版本之后,dropIndex 操作在指定集合上獲取一個排它鎖,阻塞對集合的所有后續操作
示例
-
通過索引名稱刪除
db.pets.dropIndex( "cat_-1" )
-
通過索引規范文檔刪除
db.pets.dropIndex( { "cat" : -1 } )
de.collection.dropIndexes
- 刪除單個或多個索引
- 不能刪除默認創建在
_id
字段上的索引
格式
db.collection.dropIndex(indexes)
-
indexes
-
類型:字符串、文檔、字符串數組
-
描述:需要刪除的索引
-
刪除
_id
之外的所有索引,忽略該參數 -
刪除單個索引,指定索引的名稱或索引規范文檔,text 類型的索引只能指定名稱
-
刪除多個索引,通過數組指定索引的名稱
如果數組中包含不存在的索引,則不刪除任何索引,操作報錯
4.2 新增
-
-
排它鎖
- 4.2 版本之前,dropIndex 操作在父級數據庫上獲取一個排它鎖,阻塞所有對數據庫及其所有集合的操作,直到操作完成
- 4.2 版本之后,dropIndex 操作在指定集合上獲取一個排它鎖,阻塞對集合的所有后續操作
示例
-
刪除
_id
之外的所有索引db.collection.dropIndexes()
-
刪除單個索引
db.collection.dropIndexes( { a: 1, b: 1 } ) db.collection.dropIndexes( "a_1_b_1" )
-
刪除多個索引
db.collection.dropIndexes( [ "a_1_b_1", "a_1", "a_1__id_-1" ] )
索引類型
Single Field 索引
- 單字段索引
- 對於單字段索引,升序降序並不重要,因為mongodb可以按任意方向遍歷索引
示例
db.collection.createIndex( { orderDate: 1 } )
- 在 orderDate 字段上創建一個升序索引
- 默認名稱
orderDate_1
Compound 索引
-
復合索引
-
將多個字段組合成一個索引
-
創建復合索引時,字段的順序非常重要
-
整體上按第一個字段進行排序,對於按第一個字段排序並列的索引,再使用第二個字段進行排序
-
查詢條件中必須包含索引的前綴字段
例如以3個字段組成的索引,查詢條件中需包含第一個字段 或 第一個及第二個字段 或 全部三個字段
-
復合索引中不能包含 hashed 索引
示例
db.collection.createIndex( { orderDate: 1, zipcode: -1 } )
- 創建一個在 orderDate 字段進行升序排列,在 zipcode 字段進行降序排列的復合索引
Multikey 索引
- 多鍵索引
- 使用點表示法,對嵌套數組中的字段建立索引
- mongodb會為數組中的每個元素創建單獨的 索引項
- 允許查詢條件匹配數組的一個或多個元素來選擇符合條件的文檔
- 如果索引字段包含數組元素,mongodb會自動創建一個多鍵索引
Geospatial 索引
- 地理空間索引
Text 索引
- 文本索引:對字符串內容進行查詢
- 一般在 字符串類型字段 或 字符串數組類型字段 上創建文本索引
- 使用文本索引查找時,不區分字母大小寫
- 目前不支持中文文本索引,支持英語、法語、德語、俄語、西班牙語、土耳其語
- 文本索引具有 sparse 屬性,忽略創建過程中的 sparse 選項
- 文本索引支持
$text
查詢操作 - 限制
- 一個集合最多只能創建一個文檔索引
- 排序操作 sort,不能使用文本索引中的排序
- 復合文本索引中,如果在文本索引鍵之前包含其他鍵,則通過 $text 搜索時,查詢謂詞必須包含前面鍵的相等匹配條件
- 只能通過索引名稱刪除文本索引
格式
db.collection.createIndex(
keys ,
options
)
-
keys
-
類型:Document
-
描述:text 類型的索引規范文檔
-
單字段
{ field1: "text"}
-
多字段
{ field1: "text", field2: "text", ... } // 復合索引 { field1: 1, field2: "text", ... }
-
全部字段
用
$**
代表文檔中的所有字符串類型的字段{ "$**": "text" }
-
-
-
options
- weights
- 類型:Document
- 描述:
- 包含字段和權重的文檔,指定字段的權重,默認值為1,可設定為 1-99999 之間的整數
- 優先查詢權重大的字段,次之查詢權重小的字段
- default_language
- 類型:字符串
- 描述
- 對於文本索引,不同的語言有不同的分析規則
- 默認值為
english
- language_override
- 類型:字符串
- 描述
- For text indexes, the name of the field, in the collection’s documents, that contains the override language for the document
- 默認值為
language
- textIndexVersion
- 類型:integer
- 描述:指定文本索引的版本
- weights
示例
-
創建文本索引
db.reviews.createIndex( { comments: "text" } ) db.reviews.createIndex( { subject: "text", comments: "text" } ) db.reviews.createIndex( { "$**": "text" } )
-
指定不同的權重
db.reviews.createIndex( { "$**": "text" } , { weights : {subject: 10, comments: 5}} )
- 索引名
$**_text
- 索引名
Hashed 索引
-
哈希索引:使用字段值的哈希值來創建索引
-
主要用在分片的片鍵上
-
支持 非數組 單字段 索引,不支持多字段索引
多字段索引報錯
db.articles.createIndex({subject:"hashed",author:"hashed"})
- "errmsg" : "Currently only single field hashed index supported."
數組字段索引報錯
db.articles.createIndex({arr:"hashed"})
-
"errmsg" : "Error: hashed indexes do not currently support array values",
-
creating a hashed index on a field that contains an array or attempting to insert an array into a hashed indexed field returns an error.
-
不能設定唯一性約束,因為存在hash碰撞
db.articles.createIndex({subject:"hashed"},{unique:true})
- "errmsg" : "Currently hashed indexes cannot guarantee uniqueness. Use a regular index."
-
創建哈希索引的字段,也可以同時創建其他索引
不支持創建復合索引,但是同一個字段可以創建多個不同類型的索引
db.articles.createIndex({subject:"hashed"}) db.articles.createIndex({subject:"hashed",subject:"text"}) // 只會創建一個文本索引 db.articles.createIndex({subject:"hashed",subject:1}) // 只會創建一個升序索引 // 最終在 subject 字段上創建了3個不同類型的索引
-
哈希索引支持相等查詢,不支持范圍查詢
-
在使用哈希索引查詢時,mongodb 會自動計算,無需單獨計算
4.0 版本開始,mongodb提供了
convertShardKeyToHashed()
方法,該方法使用相同的哈希計算方法,可用於查看鍵的哈希值 -
類型為浮點數的字段不能創建哈希索引
mongodb 哈希索引在計算之前會將浮點數截斷為64位的整數,例如 2.3、 2.2、 2.9 都被截斷為2進行計算
格式
db.collection.createIndex( { field: "hashed" } )
索引屬性
Unique 索引
- 唯一性
Partial 索引
- 局部性
Sparse 索引
- 稀疏性
TTL 索引
-
生命周期性(文檔在一段時間后會被mongodb自動刪除)
-
一般在 Date類型的字段 或 包含Date類型元素的數組字段 上創建TTL索引,其他字段無效
-
過期閾值的計算
- 如果字段類型是 Date,則過期閾值是字段值日期加上指定的過期時間
- 如果字段類型是包含 Date 類型元素的數組,則過期閾值是元素中最早的日期加上指定的過期時間
- 如果非以上兩種類型,TTL 索引無效,文檔不會過期
-
將
expireAfterSeconds
設置為0,則過期時間就是日期字段的值 -
TTL 線程
- mongod 中的后台線程,每隔60秒運行一次,用來讀取索引中的值並從集合中刪除過期的文檔
- 不保證文檔過期后立即被刪除,文檔過期的時間和從數據庫中刪除的時間存在延遲(60s)
- 當 TTL 線程處於活動狀態時,可以在
db.currentOp()
的輸出中看到刪除操作
-
限制
-
不能在
_id
字段上建立 TTL 索引 -
不能通過改變 options 將非 TTL 索引變為 TTL 索引
-
不能在固定集合中建立 TTL 索引,因為mongodb不能從固定集合中刪除文檔
-
不能是復合索引,只能是單字段索引
-
格式
db.collection.createIndex(
<keys>,
{
expireAfterSeconds: <integer>
}
)
示例
文檔
db.ttl.insertMany([
{date:new Date("2020-08-13T17:50:00"), money:1},
{date:new Date("2020-08-13T17:52:00"), money:2},
{date:new Date("2020-08-13T17:54:00"), money:3},
])
db.ttl.createIndex({date:-1})
db.ttl.createIndex({date:1, money:-1})
db.ttl.createIndex({date:1},{expireAfterSeconds:10})
- 在 ttl 集合中的 date 字段上創建3個索引
- 有一個 TTL 索引,過期閾值為:date 日期加上指定過期時間
- 結果是,到過期閾值時,文檔被依次刪除
修改過期時間
db.runCommand({
collMod: <collection>,
index:{
keyPattern: <keys>,
expireAfterSeconds: <integer>
}
})
示例
db.ttl.insertMany([
{date:new Date("2020-08-13T18:08:00"), money:1},
{date:new Date("2020-08-13T18:09:00"), money:2},
{date:new Date("2020-08-13T18:10:00"), money:3},
])
db.runCommand({
collMod:"ttl",
index:{
keyPattern:{date:1},
expireAfterSeconds:60*60
}
})
返回結果
{ "expireAfterSeconds_old" : 10, "expireAfterSeconds_new" : 3600, "ok" : 1 }
Hidden 索引
4.4 新增
- 對查詢規划器不可見,不能用於查詢
- 用來評估刪除索引的潛在影響,而不必實際刪除該索引。如果影響是負面的,用戶可以取消隱藏索引,而不必重新創建
- 索引在隱藏時也會被維護,因此一旦不隱藏,就可以立即使用這些索引