標籤:mongodb、nosql
一、MongoDB索引
1、索引介紹
索引在mongodb中被支援,如果沒有索引,mongodb必須掃描每一個文檔集合選擇匹配的查詢記錄。這樣掃描集合效率並不高,因為它需要mongod進程使用大量的資料作遍曆操作。 索引是一種特殊的資料結構,它儲存了小部分簡單的集合資料。索引儲存了一些特殊欄位,並將其排序。
從根本上講,索引在mongodb中和其他資料庫系統是類似的。mongodb規定了索引的集合層級、支援索引任何欄位或者子欄位在mongodb文檔集合中。
2、索引最佳化查詢方案
3、排序返回資料
來看看一個索引的具體例子(其實就相當於我們查詢欄位一樣的)
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/74/4C/wKiom1YYiRSyyRnvAAFZDyc7LAM551.jpg" title="1.png" alt="wKiom1YYiRSyyRnvAAFZDyc7LAM551.jpg" />
4、索引類型
MongoDB提供了一些不同的索引類型支援的資料和查詢的具體類型
# 查詢articles集合的索引db.articles.getIndexes();# 添加titlei欄位索引,並且為升序db.articles.ensureIndex({title:1});#重構索引(慎用)db.articles.reIndex();
注意:索引定序升序:1,降序-1
{ "_id": ObjectId(...), "item": "Banana", "category": ["food", "produce", "grocery"], "location": "4th Street Store", "stock": 4, "type": "cases", "arrival": Date(...)}
建立方法:
# 建立item、stock欄位的複合索引,並且升序排序 db.products.ensureIndex( { "item": 1, "stock": 1 } )注意:Hashed 欄位不能建立索引,如果建立將出現錯誤Application Sort Order 使用案例:降序使用者名稱升序時間。# 查詢結果集中排序 db.events.find().sort( { username: -1, date: 1 } )# 查詢結果集中排序db.user_scores.find().sort({score:-1,date:-1}).limit(1)
官方文檔中給出這樣一個案例:
{ userid:"marker", address:[ {zip:"618255"}, {zip:"618254"} ]}# 建立索引,並將zip升序排列db.users.ensureIndex({"address.zip": 1});# 假如我們做這樣的查詢db.users.find({"addr":{"$in":[{zip:"618254"}]}})
注意:你可以建立 多鍵複合索引(multikey compound indexes)
db.places.ensureIndex( { loc : "2dsphere" } )
# 建立文本索引 db.articles.ensureIndex({content:"text"});
複合索引可以包含文本索引 稱為:複合文本索引(compound text indexes),但有限制 :
(If the compound text index includes keys preceding the text index key, to perform a $text search, the query
predicate must include equality match conditions on the preceding keys1)
# 給user_scores的score欄位建立一個雜湊索引
db.user_scores.ensureIndex( { score: "hashed" } )
5、索引的屬性
除了眾多索引類型的支援以外,還可以使用各種屬性來調整效能。
使用限制:
不支援複合索引
必須是date時間類型欄位
如果是date數組,按照最早時間到期。
注意:TTL index不保證到期時間立即刪除,,背景工作沒60秒運行刪除, 依賴於mongod進程。
# 建立唯一索引db.members.ensureIndex( { "user_id": 1 }, { unique: true } )
注意:如果欄位為null,那麼就以null值,但不能重複插入空值。如果collection中有兩個實體唯一索引欄位為空白,則不能建立唯一索引
也就是說,我們還可以利用它作為類似於關係型資料庫的唯一約束。
# 強制插入空值對象後報錯> db.users.insert({content:"unique testing"})WriteResult({ "nInserted" : 0, "writeError" : { "code" : 11000, "errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.users.$dsadsadsa dup key: { : null }" }})
db.addresses.ensureIndex( { "xmpp_id": 1 }, { sparse: true } )
db.addresses.ensureIndex( { "xmpp_id": 1 }, {background: true } )
我們知道如果阻塞所有請求,建立索引就會很快,但是使用系統的使用者就需要等待,影響了資料庫的操作,因此可以更具具體情況來選擇使用background屬性
6、索引名稱
# 自動產生索引名稱db.products.ensureIndex( { item: 1, quantity: -1 } )# 被命名為: item_1_quantity_-1# 自訂索引名稱db.products.ensureIndex( { item: 1, quantity: -1 } , { name: "inventory" } )
7 、管理索引
# 添加/修改索引db.users.ensureIndex({name:"text"});# 刪除集合所有索引db.users.dropIndexes();# 刪除特定索引 (刪除id欄位升序的索引)db.users.dropIndex({"id":1})# 擷取集合索引db.users.getIndexes();# 重構索引db.users.reIndex();
8、索引分類
二、應用舉例
建立單欄位索引:
> db.testcoll.ensureIndex({Name: 1})> db.testcoll.getIndexes()[ { "v" : 1, "name" : "_id_", "key" : { "_id" : 1 }, "ns" : "test.testcoll" }, { "v" : 1, "name" : "Name_1", "key" : { "Name" : 1 }, "ns" : "test.testcoll" }]
建立雜湊索引:
> db.testcoll.ensureIndex({Name: "hashed"})> db.testcoll.getIndexes()[ { "v" : 1, "name" : "_id_", "key" : { "_id" : 1 }, "ns" : "test.testcoll" }, { "v" : 1, "name" : "Name_1", "key" : { "Name" : 1 }, "ns" : "test.testcoll" }, { "v" : 1, "name" : "Name_hashed", "key" : { "Name" : "hashed" }, "ns" : "test.testcoll" }]
刪除雜湊索引:
> db.testcoll.dropIndex("Name_hashed"){ "nIndexesWas" : 3, "ok" : 1 }> db.testcoll.getIndexes()[ { "v" : 1, "name" : "_id_", "key" : { "_id" : 1 }, "ns" : "test.testcoll" }, { "v" : 1, "name" : "Name_1", "key" : { "Name" : 1 }, "ns" : "test.testcoll" }]
刪除單欄位索引:
> db.testcoll.dropIndex({Name: 1}){ "nIndexesWas" : 2, "ok" : 1 }> db.testcoll.getIndexes()[ { "v" : 1, "name" : "_id_", "key" : { "_id" : 1 }, "ns" : "test.testcoll" }]
刪除所有索引:
> db.testcoll.dropIndexes()
查看索引是否用到:
> db.testcoll.find({Name: "User:88"}).explain(){"cursor" : "BasicCursor","isMultiKey" : false,"n" : 1,"nscannedObjects" : 100,"nscanned" : 100,"nscannedObjectsAllPlans" : 100,"nscannedAllPlans" : 100,"scanAndOrder" : false,"indexOnly" : false,"nYields" : 0,"nChunkSkips" : 0,"millis" : 42,"indexBounds" : {},"server" : "www.example.com:27017"}> db.testcoll.find().count()100
通過建立索引可以發現在查詢時只需要一次就行,不用在全文檔掃描:
> db.testcoll.ensureIndex({Name: 1}),{unique: true}{ "unique" : true }> db.testcoll.find({Name: "User:88"}).explain(){"cursor" : "BtreeCursor Name_1","isMultiKey" : false,"n" : 1,"nscannedObjects" : 1,"nscanned" : 1,"nscannedObjectsAllPlans" : 1,"nscannedAllPlans" : 1,"scanAndOrder" : false,"indexOnly" : false,"nYields" : 0,"nChunkSkips" : 0,"millis" : 0,"indexBounds" : {"Name" : [["User:88","User:88"]]},"server" : "www.example.com:27017"}
指定索引查詢:
> db.testcoll.find({Name: "User:88"}).hint({Name: 1}).explain()
總結:
前面只是簡單的介紹了MongoDB的索引及其的使用,在查詢時我們最好可以根據建立的索引來進行查詢,這樣做可以大大節省磁碟IO的開銷。若查詢時沒有相關的索引則極可能遍曆全部文檔,這樣大大降低了效能。在實際使用中建立和使用索引要做到:根據實際的需求建立最合適索引,查詢時也要使用最合適的索引。對於索引的使用前面所講的只是一些皮毛知識,若想深入學習建議可以查閱《資料庫索引設計與最佳化》。
本文出自 “粗茶淡飯” 部落格,請務必保留此出處http://cuchadanfan.blog.51cto.com/9940284/1701493
MongoDB(三)