快速掌握 MongoDB:索引詳解及實操,explain()

快速掌握 MongoDB:索引詳解及實操,explain()

每一個成功人士的背後,必定曾經做出過勇敢而又孤獨的決定。

放棄不難,但堅持很酷~

在項目開發中需要對 MongoDB 查詢進行優化,在網上查閱資料的時候發現了一篇好文章,對 MongoDB 索引介紹的挺清楚的,非常適合 MongoDB 新手閱讀。

參考鏈接:https://www.cnblogs.com/wyy1234/p/11032163.html

一、MongoDB 索引的管理

本節介紹 MongoDB 中的索引,熟悉 mysql/sqlserver 等關係型數據庫的小夥伴應該都知道索引對優化數據查詢的重要性。我們先簡單瞭解一下索引:索引的本質就是一個排序的列表,在這個列表中存儲著索引的值和包含這個值的數據(數據 row 或者 document 的物理地址,索引可以大大加快查詢的速度,這是因為使用索引後可以不再掃描全表來定位某行的數據,而是先通過索引表找到該行數據對應的物理地址(多數為 B-tree 查找),然後通過地址來訪問相應的數據。

索引可以加快數據檢索、排序、分組的速度,減少磁盤 I/O ,但是索引也不是越多越好,因為索引本身也是數據表,需要佔用存儲空間,同時索引需要數據庫進行維護,當我們對索引列的值進行增改刪操作時,數據庫需要更新索引表,這會增加數據庫的壓力。

我們要根據實際情況來判斷哪些列適合添加索引,哪些列不適合添加索引,一般遵循的規律如下:

  • 主/外鍵列,主鍵用於強制該列的唯一性和組織表中數據的排列結構;外鍵可以加快連接的速度;

  • 經常用於比較的類(大於小於等於等),因為索引已經排序,值就是大於/小於的分界點;

  • 經常進行範圍搜索,因為索引已經排序,其指定的範圍是連續的;

  • 經常進行排序的列,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;

  • 經常進行分組的列,因為索引已經排序,同一個值的所有數據地址會聚集在一塊,很方便分組。

我們看一下 MongoDB 的索引使用,首先往 userinfos 集合中插入一些數據:

<code>db.userinfos.insertMany([
{_id:1, name: "張三", age: 23,level:10, ename: { firstname: "san", lastname: "zhang"}, roles: ["vip","gen" ]},
{_id:2, name: "李四", age: 24,level:20, ename: { firstname: "si", lastname: "li"}, roles:[ "vip" ]},
{_id:3, name: "王五", age: 25,level:30, ename: { firstname: "wu", lastname: "wang"}, roles: ["gen","vip" ]},
{_id:4, name: "趙六", age: 26,level:40, ename: { firstname: "liu", lastname: "zhao"}, roles: ["gen"] },
{_id:5, name: "田七", age: 27, ename: { firstname: "qi", lastname: "tian"}, address:'北京' },
{_id:6, name: "周八", age: 28,roles:["gen"], address:'上海' }
]);
/<code>

索引的增刪改查還是十分簡單的,我們看一下索引管理的幾個方法:

<code>// 創建索引,值 1 表示正序排序,-1 表示倒序排序;background 為 true 表示索引在後臺創建,默認為false。
db.userinfos.createIndex({age: -1}, {background: true})

// 查看userinfos中的所有索引
db.userinfos.getIndexes

// 刪除特定一個索引
db.userinfos.dropIndex({name:1,age:-1})

// 刪除所有的索引(主鍵索引_id不會被刪除)
db.userinfos.dropIndexes

// 如果我們要修改一個索引的話,可以先刪除索引然後在重新添加。
/<code>

二、MongoDB 中常用的索引類型

1、單鍵索引

單鍵索引( Single Field Indexes )顧名思義就是單個字段作為索引列,MongoDB 的所有 collection 默認都有一個單鍵索引 _id ,我們也可以對一些經常作為過濾條件的字段設置索引,如給 age 字段添加一個索引,語法十分簡單:

<code>// 給age字段添加升序索引
db.userinfos.createIndex({age:1})
/<code>

其中 {age:1} 中的 1 表示升序,如果想設置倒序索引的話使用 db.userinfos.createIndex({age:-1}) 即可。我們通過 explain 方法查看查詢計劃,如下圖,看到查詢 age=23 的 document 時使用了索引,如果沒有使用索引的話stage 為 COLLSCAN 。

快速掌握 MongoDB:索引详解及实操,explain()

因為 document 的存儲是 bson 格式的,我們也可以給內置對象的字段添加索引,或者將整個內置對象作為一個索引,語法如下:

<code>// 1.內嵌對象的某一字段作為索引
// 在ename.firstname字段上添加索引
db.userinfos.createIndex({"ename.firstname":1})
// 使用ename.firstname字段的索引查詢
db.userinfos.find({"ename.firstname":"san"})

// 2.整個內嵌對象作為索引
// 給整個ename字段添加索引
db.userinfos.dropIndexes
// 使用ename字段的索引查詢
db.userinfos.createIndex({"ename":1})
/<code>

2、複合索引

複合索引( Compound Indexes )指一個索引包含多個字段,用法和單鍵索引基本一致。使用複合索引時要注意字段的順序,如下添加一個 name 和 age 的複合索引,name 正序,age 倒序,document 首先按照 name 正序排序,然後 name 相同的 document 按 age 進行倒序排序。MongoDB 中一個複合索引最多可以包含 32 個字段。

<code>// 添加複合索引,name正序,age倒序
db.userinfos.createIndex({"name":1,"age":-1})

// 過濾條件為name,或包含name的查詢會使用索引(索引的第一個字段)
db.userinfos.find({name:'張三'}).explain

db.userinfos.find({name:"張三",level:10}).explain
db.userinfos.find({name:"張三",age:23}).explain

// 查詢條件為age時,不會使用上邊創建的索引,而是使用的全表掃描
db.userinfos.find({age:23}).explain
/<code>

執行查詢時查詢計劃如下:

快速掌握 MongoDB:索引详解及实操,explain()

3、多鍵索引

多鍵索引 ( mutiKey Indexes ) 是建在數組上的索引,在 MongoDB 的 document 中,有些字段的值為數組,多鍵索引就是為了提高查詢這些數組的效率。看一個栗子:準備測試數據,classes 集合中添加兩個班級,每個班級都有一個 students 數組,如下:

<code>db.classes.insertMany([
{
"classname":"class1",
"students":[{name:'jack',age:20},
{name:'tom',age:22},
{name:'lilei',age:25}]
},
{
"classname":"class2",
"students":[{name:'lucy',age:20},
{name:'jim',age:23},
{name:'jarry',age:26}]
}]
)
/<code>

為了提高查詢 students 的效率,我們使用 db.classes.createIndex({'students.age':1}) 給 students 的 age 字段添加索引,age 是數組中的字段哦,然後使用索引,如下圖:

快速掌握 MongoDB:索引详解及实操,explain()

4、哈希索引

哈希索引( hashed Indexes )就是將 field 的值進行 hash 計算後作為索引,其強大之處在於實現 O(1) 查找,當然用哈希索引最主要的功能也就是實現定值查找,對於經常需要排序或查詢範圍查詢的集合不要使用哈希索引

快速掌握 MongoDB:索引详解及实操,explain()

三、MongoDB中常用的索引屬性

1、唯一索引

唯一索引 (unique indexes) 用於為 collection 添加唯一約束,即強制要求 collection 中的索引字段沒有重複值。添加唯一索引的語法:

<code>// 在userinfos的name字段添加唯一索引
db.userinfos.createIndex({name:1},{unique:true})
/<code>

看一個使用唯一索引的栗子:

快速掌握 MongoDB:索引详解及实操,explain()

2、局部索引

局部索引 (Partial Indexes) 顧名思義,只對 collection 的一部分添加索引。創建索引的時候,根據過濾條件判斷是否對 document 添加索引,對於沒有添加索引的文檔查找時採用的全表掃描,對添加了索引的文檔查找時使用索引。使用方法也比較簡單:

<code>//userinfos集合中age>25的部分添加age字段索引
db.userinfos.createIndex(
{age:1},
{partialFilterExpression: {age:{$gt: 25 }}}
)

//查詢age<25的document時,因為age<25的部分沒有索引,會全表掃描查找(stage:COLLSCAN)
db.userinfos.find({age:23})

//查詢age>25的document時,因為age>25的部分創建了索引,會使用索引進行查找(stage:IXSCAN)
db.userinfos.find({age:26})
/<code>

當查詢 age=23 的記錄時,stage 為 COLLSCAN,當查詢 age=26 的記錄時,使用了索引,如下:

快速掌握 MongoDB:索引详解及实操,explain()

3、稀疏索引

稀疏索引 (sparse indexes) 在有索引字段的 document 上添加索引,如在 address 字段上添加稀疏索引時,只有 document 有 address 字段時才會添加索引。而普通索引則是為所有的 document 添加索引,使用普通索引時如果 document 沒有索引字段的話,設置索引字段的值為 。

稀疏索引的創建方式如下,當document包含address字段時才會創建索引:

<code>//創建在address上創建稀疏索引
db.userinfos.createIndex({address:1},{sparse:true})
/<code>

看一個使用稀疏索引的栗子:

快速掌握 MongoDB:索引详解及实操,explain()

4、TTL索引

TTL索引 (TTL indexes) 是一種特殊的單鍵索引,用於設置 document 的過期時間,MongoDB 會在 document 過期後將其刪除,TTL 非常容易實現類似緩存過期策略的功能。我們看一個使用 TTL 索引的栗子:

<code>// 添加測試數據
db.logs.insertMany([
{_id:1,createtime:new Date(),msg:"log1"},
{_id:2,createtime:new Date(),msg:"log2"},
{_id:3,createtime:new Date(),msg:"log3"},
{_id:4,createtime:new Date(),msg:"log4"}
])

// 在createtime字段添加TTL索引,過期時間是120s
db.logs.createIndex({createtime:1}, { expireAfterSeconds: 120 })

// logs中的document在創建後的120s後過期,會被mongoDB自動刪除
/<code>

注意:TTL索引只能設置在 date 類型字段(或者包含 date 類型的數組)上,過期時間為字段值 +exprireAfterSeconds ;document 過期時不一定就會被立即刪除,因為 MongoDB 執行刪除任務的時間間隔是60s;capped Collection(固定集合) 不能設置 TTL 索引,因為 MongoDB 不能主動刪除 capped Collection 中的 document 。

四、總結

本文介紹了 MongoDB 中常用的索引和索引屬性,索引對提升數據檢索的速度十分重要,在數據量比較大的時候一般都要在 collection 上建立索引。在建立索引的測試中,可以使用 explain 方法來查看 MongoDB 在語句查詢中走沒走索引,一般就是看 queryPlanner.winningPlan.inputStage.stage 屬性,IXSCAN 表示走索引掃描,COLLSCAN 表示走集合掃描。

MongoDB 提供的索引種類很豐富,總會有幾種適用於我們的業務,除了上邊介紹的索引外,MongoDB 還支持 text index 和 一些地理位置 相關的索引,這裡不再介紹,有興趣的小夥伴可以到官網研究下。

官網地址:https://docs.mongodb.com/manual/indexes/

點關注,不迷路

好了各位,以上就是這篇文章的全部內容了,能看到這裡的人呀,都是人才

白嫖不好,創作不易。各位的支持和認可,就是我創作的最大動力,我們下篇文章見!

如果本篇博客有任何錯誤,請批評指教,不勝感激 !

☞ Ambari 2.7.3.0 安裝部署 hadoop 3.1.0.0 集群視頻完整版

☞ 【實戰】使用 Kettle 工具將 mysql 數據增量導入到 MongoDB 中

☞ 都快2020年了,ambari自定義服務集成,你還沒掌握嗎?文末有福利

☞ HBase原理(一):架構理解

☞ HBase二次開發之搭建HBase調試環境,如何遠程debug HBase源代碼

☞ Kafka消費者 之 指定位移消費

☞ Kylin配置Spark並構建Cube(修訂版)

☞ 看完您如果還不明白 Kerberos 原理,算我輸!

歡迎大家留言討論

朕已閱 快速掌握 MongoDB:索引詳解及實操,explain()


分享到:


相關文章: