使用索引可以大大提高文檔的查詢效率。如果沒有索引,會遍歷集合中所有文檔,才能找到匹配查詢語句的文檔。這樣遍歷集合中整個文檔的方式是非常耗時的,特別是處理大數據時,耗時幾十秒甚至幾分鍾都是有可能的。
創建索引
MongoDB 中,使用 ensureIndex() 方法創建索引。
格式
db.COLLECTION_NAME.ensureIndex({KEY:1})
其中,KEY表示要創建索引的字段名稱,1 表示按升序排列字段值。-1 表示按降序排列。
范例
1、給 user 集合中 name 字段添加索引
>db.user.ensureIndex({"name":1}) >
MongoDB 中用 db.collection.getIndexes() 方法查詢集合中所有的索引,我們查詢一下 user 中所有的索引。
>db.user.getIndexes() [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "liruihuan.user" }, { "v" : 2, "key" : { "age" : 1 }, "name" : "name_1", "ns" : "liruihuan.user" } ]
我們發現 user 中有兩個索引,其中索引 "_id_" 是我們創建 user 集合時,MongoDB 自動生成的索引。第二個索引就是我們剛才創建的索引,其中,name 值"name_1"表示索引名稱,MongoDB 會自動生成的索引名稱。當然,我們也可以自己指定索引的名稱。
2、給 user 集合中 age 字段添加索引,並指定索引名稱為 "index_age_esc"。
>db.user.ensureIndex({"age":1},{name:"index_age_esc"}) >db.user.getIndexes() [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "liruihuan.user" }, { "v" : 2, "key" : { "age" : 1 }, "name" : "index_age_esc", "ns" : "liruihuan.user" } ]
指定索引名稱用到的 name 參數,只是 ensureIndex() 方法可接收可選參數的其中一個,下表列出了 ensureIndex() 方法可接收的參數
Parameter | Type | Description |
---|---|---|
background | 布爾值 | 建索引過程會阻塞其它數據庫操作,background可指定以后台方式創建索引,即增加 "background" 可選參數。 "background" 默認值為false。 |
unique | 布爾值 | 建立的索引是否唯一。指定為true創建唯一索引。默認值為false. |
name | 字符串 | 索引的名稱。如果未指定,MongoDB的通過連接索引的字段名和排序順序生成一個索引名稱。 |
dropDups | 布爾值 | 在建立唯一索引時是否刪除重復記錄,指定 true 創建唯一索引。默認值為 false. |
sparse | 布爾值 | 對文檔中不存在的字段數據不啟用索引;這個參數需要特別注意,如果設置為true的話,在索引字段中不會查詢出不包含對應字段的文檔.。默認值為 false. |
expireAfterSeconds | 整型 | 指定一個以秒為單位的數值,完成 TTL設定,設定集合的生存時間。 |
v | 索引版本 | 索引的版本號。默認的索引版本取決於mongod創建索引時運行的版本。 |
weights | 文檔(document) | 索引權重值,數值在 1 到 99,999 之間,表示該索引相對於其他索引字段的得分權重。 |
default_language | 字符串 | 對於文本索引,該參數決定了停用詞及詞干和詞器的規則的列表。 默認為英語 |
language_override | 字符串 | 對於文本索引,該參數指定了包含在文檔中的字段名,語言覆蓋默認的language,默認值為 language. |
唯一索引
MongoDB和關系型數據庫一樣都可以建立唯一索引,重復的鍵值就不能重新插入了,MongoDB 用 unigue 來確定建立的索引是否為唯一索引,true 表示為唯一索引,下面給 user 集合的 name 字段指定唯一索引
>db.user.ensureIndex({"name":1},{unique:true}) > db.user.find() { "_id" : ObjectId("58e1d2f0bb1bbc3245fa754b"), "name" : "liruihuan", "age" : 18,"sex":"man" } >db.user.insert({"name":"liruihuan","age":18}) E11000 duplicate key error collection: liruihuan.user index: name_1 dup key: { : \"liruihuan\"
可以看出,創建了唯一索引的字段,是不能再插入 "liruihuan" 的 name 值的。
復合索引
ensureIndex() 方法中你也可以設置使用多個字段創建索引
范例
>db.user.ensureIndex({"name":1,"age":1}) >db.user.getIndexes() [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "liruihuan.user" }, { "v" : 2, "key" : { "name" : 1, "age" : 1 }, "name" : "name_1_age_1", "ns" : "liruihuan.user" } ]
刪除索引
MongoDB 用dropIndex() 方法刪除索引
格式
db.COLLECTION_NAME.dropIndex()
注:dropIndex() 方法可根據指定的索引名稱或索引文檔刪除索引(_id上的默認索引除外)
范例
我們用兩種方式刪除掉 user 中 name 字段上的索引
>db.user.dropIndex("name_1") #根據索引名稱刪除索引 >db.user.dropIndex({"name":1}) #根據索引文檔刪除索引
還可以用 dropIndexes() 刪除集合中所有索引(_id上的默認索引除外)
>db.user.dropIndexes()
查詢分析
查詢分析是查詢語句性能分析的重要工具。
MongoDB 中查詢分析用 explain() 和 hint() 方法
范例
我們向集合 user 中插入20萬條數據,利用 explain() 查詢建立索引前后,執行時間的比較,來看看建立索引對查詢效率的提高程度。
第一步,向 user 中插入20萬條數據
>db.user.remove({}) >for(var i = 0; i <200000; i++){db.user.insert({"name":"lrh"+i,"age":18})}
第二步,刪除 user 集合中字段 name 上的索引,然后查詢 name = "lrh100000",利用explain("executionStats")查詢此時執行的時間。說明:MongoDB explain() 方法在3.0以后版本中發生了很大改變,3.0之前版本直接用explain()就可以,不用傳參數,如果想詳細了解,請訪問官網。
>db.user.dropIndexes() #刪除所有索引 db.user.find({"name":"lrh100000"}).explain("executionStats") { "queryplanner" : { ...... }, "executionStats" : { "executionTimeMillis" : 109 ...... } }
explain.executionStats.executionTimeMillis:表示查詢所用的時間,單位是毫秒。
我們可以清楚的看出,沒用索引查詢用到的時間是 109 毫秒。
第三步,給 user 集合中 name 字段添加索引,然后再查詢同一個條件,看執行查詢所用了多久時間。
>db.user.ensureIndex({"name":1}) >db.user.find({"name":"lrh100000"}).explain("executionStats") { "queryplanner" : { "winningPlan" : { "inputStage" : { "indexName" : "name_1" ...... } ....... } ....... }, "executionStats" : { "executionTimeMillis" : 1 ...... } }
如果用到了索引,explain() 方法會返回 winningPlan,標識用到的索引名稱 indexName
我們可以清楚到處,用了索引,執行時間只有 1 毫秒,可以看出,查詢效率的提高可不是一星半點。
注:如果想更詳細的了解 explain() 返回的參數,可以去官網看一下
第四步,這一步我們重點看看 hint() 方法的用法。hint() 方法用來強制 MongoDB 使用一個指定的索引。
我們給 user 再添加一個 {"name":1, "age":1},利用 explain() 方法,看一下用到了哪個索引。
>db.user.ensureIndex({"name":1, "age":1}) >db.user.find({"name":"lrh100000"}).explain("executionStats") { "queryplanner" : { "winningPlan" : { "inputStage" : { "indexName" : "name_1_age_1" ...... } ....... } ....... } ...... }
可以看出,此時用到的索引是 "name_1_age_1",如果我們想用索引 "name_1",就可以用 hint() 方法指定。
>db.user.find({"name":"lrh100000"}).hint({"name":1}).explain("executionStats") { "queryplanner" : { "winningPlan" : { "inputStage" : { "indexName" : "name_1" ...... } ....... } ....... } ...... }
業精於勤,荒於嬉;行成於思,毀於隨。
如果你覺得這篇文章不錯或者對你有所幫助,可以通過右側【打賞】功能,給予博主一點點鼓勵和支持