1. 程式人生 > >MongoDB基礎教程系列--第六篇 MongoDB 索引

MongoDB基礎教程系列--第六篇 MongoDB 索引

https://www.cnblogs.com/liruihuan/p/6682575.html

使用索引可以大大提高文件的查詢效率。如果沒有索引,會遍歷集合中所有文件,才能找到匹配查詢語句的文件。這樣遍歷集合中整個文件的方式是非常耗時的,特別是處理大資料時,耗時幾十秒甚至幾分鐘都是有可能的。

建立索引

MongoDB 中,使用 ensureIndex() 方法建立索引。

格式

1

db.COLLECTION_NAME.ensureIndex({KEY:1})

其中,KEY表示要建立索引的欄位名稱,1 表示按升序排列欄位值。-1 表示按降序排列。

範例

1、給 user 集合中 name 欄位新增索引

1

2

>db.user.ensureIndex({"name":1})

>

MongoDB 中用 db.collection.getIndexes() 方法查詢集合中所有的索引,我們查詢一下 user 中所有的索引。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

>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"。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

>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 欄位指定唯一索引

1

2

3

4

5

6

7

>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() 方法中你也可以設定使用多個欄位建立索引

範例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

>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() 方法刪除索引

格式

1

db.COLLECTION_NAME.dropIndex()

注:dropIndex() 方法可根據指定的索引名稱或索引文件刪除索引(_id上的預設索引除外)

範例

我們用兩種方式刪除掉 user 中 name 欄位上的索引

1

2

>db.user.dropIndex("name_1")     #根據索引名稱刪除索引

>db.user.dropIndex({"name":1})   #根據索引文件刪除索引

還可以用 dropIndexes() 刪除集合中所有索引(_id上的預設索引除外)

1

>db.user.dropIndexes()

查詢分析

查詢分析是查詢語句效能分析的重要工具。

MongoDB 中查詢分析用 explain() 和 hint() 方法

範例

我們向集合 user 中插入20萬條資料,利用 explain() 查詢建立索引前後,執行時間的比較,來看看建立索引對查詢效率的提高程度。

第一步,向 user 中插入20萬條資料

1

2

>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()就可以,不用傳引數,如果想詳細瞭解,請訪問官網

1

2

3

4

5

6

7

8

9

10

11

>db.user.dropIndexes()      #刪除所有索引

db.user.find({"name":"lrh100000"}).explain("executionStats")

{

       "queryplanner" : {

                 ......

       },

       "executionStats" : {

                 "executionTimeMillis" : 109

                 ......

       }

}

explain.executionStats.executionTimeMillis:表示查詢所用的時間,單位是毫秒。

我們可以清楚的看出,沒用索引查詢用到的時間是 109 毫秒。

第三步,給 user 集合中 name 欄位新增索引,然後再查詢同一個條件,看執行查詢所用了多久時間。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

>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() 方法,看一下用到了哪個索引。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

>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() 方法指定。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

>db.user.find({"name":"lrh100000"}).hint({"name":1}).explain("executionStats")

{

       "queryplanner" : {

                 "winningPlan" : {

                        "inputStage" : {

                                 "indexName" "name_1"

                                 ......

                        }

                        .......

                 }

                .......

       }

       ......

}