1. 程式人生 > >MongoDB-6: MongoDB索引

MongoDB-6: MongoDB索引

xpl pan buffered 單個 top wid idt document 索引類型

一、簡介

在MongoDB建立索引能提高查詢效率,只需要掃描索引只存儲的這個集合的一小部分,並只把這小部分加載到內存中,效率大大的提高,如果沒有建立索引,在查詢時,MongoDB必須執行全表掃描,在數據量大時,效率差別就很明顯,對於包括一個沒有索引的排序操作的查詢,服務器必須在返回任何結果之前將所有的文檔加載到內存中來進行排序。

索引是特殊的數據結構,索引存儲在一個易於遍歷讀取的數據集合中,索引是對數據庫表中一列或多列的值進行排序的一種結構。索引項的排序支持高效的相等匹配和基於範圍的查詢操作。

從mongoDB 3.0開始ensureIndex被廢棄,使用 createIndex創建索引。

創建索引的語法:

db.collection.createIndex(keys,options) 

參數

類型

描述

keys

document

一個包含該字段的字段和值對的文檔,該文檔的索引鍵和該值描述該字段的索引類型。對於某個領域的上升索引,指定一個值為1;對於下降的索引,指定一個值為1。

MongoDB支持幾種不同的索引類型,包括文本,空間,和哈希索引。查看更多信息的索引類型。

options

document

在創建索引的時的限制條件

二、 索引的基本操作

我們先插入10w條記錄

for(var i=0;i<1000000;i++){    
.       db. orders.insert({  
         "onumber" : i,    
         "date" : "2015-07-02",    
         "cname" : "zcy"+i,    
          "items" :[ {   
                   "ino" : i,  
                  "quantity" : i,    
                  "price" : 4.0  
            },{   
                  "ino" : i+1,  
                  "quantity" : i+1,    
                  "price" : 6.0  
             }  
          
] }) }

1. 默認索引

存儲在MongoDB集合中的每個文檔(document)都有一個默認的主鍵“_id“,如果我們在添加新的文檔時,沒有指定“_id“值時,MongoDB會創建一個ObjectId值,並創建會自動創建一個索引在“_id“鍵上,默認索引的名稱是”_id_“,並無法刪除,如下面的命令查看:

>db.orders.getIndexes() 

技術分享圖片

2. 查看索引信息

返回一個數組,該數組保存標識和描述集合上現有索引的文檔列表,可以查看我們是否有對某個集合創建索引,並創建哪些索引,方便我們管理。

語法:

>db.collection.getIndexes()  

3. 創建單列索引

我們對文檔單個字段創建索引或者對內嵌文檔的單個字段創建索引

語法:

db.collection.createIndex({field:boolean} }) 

boolean:對於某個領域的上升索引,指定一個值為1;對於下降的索引,指定一個值為1。

(1)創建

例子:

db.orders.createIndex({cname:1})

技術分享圖片

我們對orders集合創建了cname索引,默認的索引名稱是”cname_1“

(2)根據條件查詢文檔,並查看查詢效率怎麽樣

例子:

db.orders.find({"cname":"zcy100000"}) 

我們查詢orders 集合根據條件cname為zcy100000的文檔

我們測試有建索引和沒建索引在1000000條文檔執行查詢的效率怎麽樣,我們這邊先使用explain()函數,下一篇我們介紹

我們這邊先介紹幾個參數

1) n:當前查詢返回的文檔數量。

2)millis:當前查詢所需時間,毫秒數。

3)indexBounds:當前查詢具體使用的索引

例子:

db.orders.find({"cname":"zcy100000"}).explain()  

1)沒建索引時,查詢條件cname為zcy100000的文檔


技術分享圖片

返回一個記錄,花費1006毫秒,沒使用到索引

2)有建索引,查詢條件cname為zcy100000的文檔

技術分享圖片

返回一個記錄,花費82毫秒,有使用到cname索引

我們結果是相差很大的,有建索引字段,查詢效率比較高,在大數據時,差別更明顯。

(3)查詢和排序組合使用

我們查詢集合cname大於zcy100的文檔並對onumber進行降序排序

例子:

db.orders.find({"cname":{$gt:"zcy1000"}}).sort({"onumber":1}).explain() 

技術分享圖片

執行出現錯誤:

"$err" : "Runner error:Overflow sort stage buffered data usage of 33554456 bytes exceeds internal limit of 33554432 bytes",

我們的內存只有33554432字節,對於包括一個沒有索引的排序操作的查詢,服務器必須在返回任何結果之前將所有的文檔加載到內存中來進行排序。

我們對onumber創建索引

db.orders.createIndex({onumber:-1}) 

技術分享圖片

技術分享圖片

這次我們在執行時,可以正常執行,已經減少了內存的緩存的數據

4. 創建組合索引

我們可以同時對多個鍵創建組合索引

語法:

db.collection.createIndex({field1:boolean, field2:boolean } }) 

明:

db.collection.createIndex({a:1,b:1,c:1 } })

我們對a、b、c進組合創建索引,支持查詢時會用到索引的幾種:

1) a

2) a,b

3) a,b,c

這三中的查詢條件,會使用到索引

(1) 創建組合索引

我們同時對onumber和cname進行組合索引

例子:

>db.orders.createIndex({cname:1,onumber:-1})  

索引存儲在一個易於遍歷讀取的數據集合中,存儲的數據

{_id:..,"onumber" : 2, "date" : "2015-07-02", "cname" : "zcy1"})

{_id:..,"onumber" : 1, "date" : "2015-07-02", "cname" : "zcy1"})

{_id:..,"onumber" : 1, "date" : "2015-07-02", "cname" : "zcy2"})

(2) 查詢

1)我們對cname和onumber作為查詢條件時

例子:

>db.orders.find({"cname":{$gt:"zcy1000"},"onumber":2000}).explain() 

技術分享圖片

我們查詢條件cname大於zcy1000並且onumber等於2000的數據,我們用explain()查詢索引使用情況


2)我們只用兩個索引其中一個作為查詢時

第一種情況:我們條件只使用"cname":{$gt:"zcy1000"}作為查詢條件

例子:

>db.orders.find({"cname":{$gt:"zcy1000"}}).explain()

技術分享圖片

會使用到索引,符合我們前面介紹的我們對a、b、c進組合創建索引,支持查詢時會用到索引的第一種。

第二種情況:我們條件只使用"onumber":2000作為查詢條件

例子:

> db.orders.find({"onumber":2000}).explain() 

技術分享圖片

不會使用到索引,不符合我們前面介紹的我們對a、b、c進組合創建索引,支持查詢時會用到幾種。

(3)查詢和排序組合使用

我們查詢集合cname大於zcy100的文檔並對onumber進行降序排序

例子:

    >db.orders.find({"cname":{$gt:"zcy1000"}}).sort({"onumber":1}).explain()  

執行出現錯誤:

"$err" : "Runner error:Overflow sort stage buffered data usage of 33554456 bytes exceeds internal limit of 33554432 bytes",

sort時,不會使用到索引,不符合我們前面介紹的我們對a、b、c進組合創建索引,支持查詢時會用到幾種。


總結:我們在使用組合索引時,查詢時會用到組合索引的前端的幾種組合。

我們對a、b、c進組合創建索引,支持查詢時會用到索引的幾種:

1) a

2) a,b

3) a,b,c

5. 內嵌文檔的索引

我們對內嵌文檔創建索引時,跟基本文檔創建索引一樣

語法:

db.collection.createIndex({field:boolean} })  

field說明:以“.“來指明內嵌文檔的路徑

(1) 單列的內嵌文檔的索引創建

例子:

    >db.orders.createIndex({"items.info":1})  

技術分享圖片

我們orders集合下的內嵌items集合的info字段創建索引

我們以items.info字段作為查詢條件,並使用索引的情況

例子:

db.orders.find({"items.info":{$lt:100}}).explain() 

技術分享圖片

我們查詢items.info小於100的數據

(2) 組合的內嵌文檔的索引的創建

我們對內嵌文檔創建組合索引時,跟基本文檔創建組合索引一樣

語法:

>db.collection.createIndex({field1:boolean, field2:boolean } })  

例子:

>db.orders.createIndex({"items.info":1, "items. quantity":-1}) 

6. 刪除索引

我們對已經創建的索引進行刪除,可以針對具體的集合中索引進行刪除,也可以對所有的集合中的所有索引刪除

(1)具體索引名稱刪除索引

語法:

db.collection.dropIndex(index) 

刪除具體的索引,根據索引名稱刪除,如果不知道索引的名稱,可以通過db.collection.getIndexes()查看索引名稱


例子:

    > db.orders.dropIndex("cname_1")  

技術分享圖片

我們刪除cname字段的索引,現在只剩下onumber字段索引

技術分享圖片

(2)刪除集合中所有索引

語法:

db.collection.dropIndexes()  

例子:

> db.orders.dropIndexes() 

技術分享圖片

我們對集合中的索引都刪除,我們刪除cname字段的索引和onumber字段索引,現在只剩默認的_id字段索引,索引我們在使用時,要謹慎,以免把集合中的索引都刪除。


(3)對dropIndexes方法,我們還有一種用法,可以指定集合的具體索引的刪除

例子:

    > db.runCommand({"dropIndexes":"orders","index":"cname_1"})  

技術分享圖片

我們刪除cname字段的索引,現在只剩下onumber字段索引

總結:

在MongoDB建立索引能提高查詢效率,但在MongoDB新增、修改效率上比較慢

MongoDB-6: MongoDB索引