MongoDB中的索引和其餘數據庫索引相似,也是使用B-Tree結構。MongoDB的索引是在collection級別上的,而且支持在任何列或者集合內的文檔的子列中建立索引。html
下面是官方給出的一個使用索引查詢和排序的一個結構圖。mongodb
全部的MongoDB集合默認都有一個惟一索引在字段「_id」上,若是應用程序沒有爲 「_id」列定義一個值,MongoDB將建立一個帶有ObjectId值的列。(ObjectId是基於 時間、計算機ID、進程ID、本地進程計數器 生成的)數據庫
MongoDB 一樣支持在一列或多列上建立升序或降序索引。數組
MongoDB還能夠建立 多鍵索引、數組索引、空間索引、text索引、哈希索引,其屬性能夠是惟一性索引、稀疏性索引、TTL(time to live)索引。服務器
索引的限制:dom
索引名稱不能超過128個字符ide
每一個集合不能超過64個索引函數
複合索引不能超過31列性能
MongoDB 索引語法測試 |
|
db.collection.createIndex({ <field>: < 1 or -1 > }) db.collection.ensureIndex({ <field>: < 1 or -1 > })
db.collection.createIndex( { "filed": sort } ) db.collection.createIndex( { "filed": sort , "filed2": sort } )
db.tab.ensureIndex({"id":1}) db.tab.ensureIndex({"id":1} ,{ name:"id_ind"}) db.tab.ensureIndex({"id":1,"name":1},{background:1,unique:1}) db.tab.ensureIndex( { "id" : "hashed" })
|
建立索引(兩種方法)
filed :爲鍵列 sort :爲排序。1 爲升序;-1爲降序。
建立單列索引 建立索引並給定索引名稱 後臺建立惟一的複合索引 建立哈希索引 (更多參數 看文章底部) |
db.tab.indexStats( { index: "id_ind" } ) db.runCommand( { indexStats: "tab", index: "id_ind" } ) db.tab.getIndexes() db.system.indexes.find() |
(前2個彷佛不能用,官方文檔解釋) (not intended for production deployments) 查看索引 |
db.tab.totalIndexSize(); |
查看索引大小 |
db.tab.reIndex() db.runCommand({reIndex:"tab"}) |
重建索引 |
db.tab.dropIndex(<indexname>) db.tab.dropIndex("id_1") db.tab.dropIndexes() |
刪除索引 <indexname>爲getIndexes看到的索引名稱 刪除全部索引(注意!) |
|
|
索引性能測試:
查看索引是否生效,分析查詢性能有沒有提升。先插入10萬數據到集合tab
for(var i=0;1<=100000;i++){
var value=parseInt(i*Math.random());
db.tab.insert({"id":i,"name":"kk"+i,"value":value});
}
不知道是否是虛擬機的緣由,插入了10分鐘都未完成!~
本身又打開文件夾查看,一直進不去文件夾。結果客戶端鏈接斷開了!~查看服務居然停了!
重啓服務,進去查看行數:96萬!(事後再查看吧!就用這數據測試了!)
db.tab.find().count()
AnalyzeQuery Performance :http://docs.mongodb.org/manual/tutorial/analyze-query-plan/
分析函數 |
|
db.tab.find({"name":"kk50000"}).explain() |
查詢name=」kk50000」的執行分析 |
db.tab.find({"name":"kk50000"}).explain("queryPlanner") db.tab.find({"name":"kk50000"}).explain("Verbosity") db.tab.find({"name":"kk50000"}).explain("executionStats") db.tab.find({"name":"kk50000"}).explain("allPlansExecution") |
這3種方法執行結果徹底包括上面這種的結果 |
db.tab.find({"name":"kk50000"}).explain() 結果作分析: |
|
"cursor" : "BasicCursor", "isMultiKey" : false, "n" : 1, "nscannedObjects" : 966423, "nscanned" : 966423, "nscannedObjectsAllPlans" : 966423, "nscannedAllPlans" : 966423, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 7555, "nChunkSkips" : 0, "millis" : 4677, "server" : "kk-ad:27017", "filterSet" : false |
遊標類型。BasicCurso(掃描), BtreeCursor(索引) 是否多鍵(組合)索引 返回行數 掃描行數 掃描行數 全部計劃掃描的次數 全部計劃掃描的次數 是否在內存中排序
耗時(毫秒) 服務器
|
如今建立索引:
db.tab.createIndex({"name":1})
db.tab.find({"name":"kk50000"}).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" : 1, "indexBounds" : { "name" : [ [ "kk50000", "kk50000" ] ] }, "server" : "kk-ad:27017", "filterSet" : false |
遊標使用索引BtreeCursor = name_1
耗時:1毫秒
|
上面能夠看到,沒使用索引時,耗時4677毫秒,使用索引後,1毫秒!~而且不用全文檔掃描。
索引提示(hint),當前collection建立的索引:
db.tab.ensureIndex({"id":1} ,{name:"id_ind"})
db.tab.ensureIndex({"id":1,"name":1},{background:1,unique:1})
db.tab.ensureIndex( { "name" :"hashed" })
如今查詢 id=5000 的行(結果集爲1行)
db.tab.find({"id": 5000}).explain()
查詢使用的是id和name的複合索引。
"nscannedObjectsAllPlans" : 2,
"nscannedAllPlans" : 2,
如今加上索引提示,強制使用索引:
db.tab.find({"id": 5000}).hint({"id":1}).explain()
這時使用的是單個鍵列爲id的索引。
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
上面還能夠看到,索引有個邊界值「indexBounds」
這個邊界值在複合索引查詢的時候,會致使掃描更多的數據。這是一個bug :wrong index ranges when using compound index on a list
固然咱們也能夠本身限制邊界值。
db.tab.find().min({"id":5000}).max({ "id":5005})
從上面看,實際只查詢這個邊界的內的數值。再查看執行計劃:
db.tab.find().min({"id":5000}).max({ "id":5005}).explain()
只是5行數據。若是查詢id=5000的,可是索引邊界又有問題,這時能夠限制邊界,如:
db.tab.find({"id": 5000 }).min({"id":5000}).max({ "id":5005})
在索引方法中,還有一個方法爲cursor.snapshot(),它會確保查詢不會屢次返回相同的文檔,即便是寫操做在一個由於文檔大小增加而移動的文檔。可是,snapshot()不能保證插入或者刪除的隔離性。snapshot()是使用在_id鍵列上的索引,所以snapshot()不能使用sort() 或 hint()。
分快照函數析snapshot()的查詢結果:
db.tab.find({"id": 5000}).snapshot().explain()
雖然使用了索引「_id」,可是把整個集合都搜索了!~
加索引提示看看,應該是報錯的:
db.tab.find({"id": 5000}).snapshot().hint({"id":1})
果真是出錯:snapshot 不能使用提示。
下面總結索引查詢的一些方法:
Indexing Query Modifiers |
|
db.tab.find({"id": 5000 }).hint({"id":1}) db.tab.find({"id": 5000 })._addSpecial("$hint",{"id":1}) db.tab.find({ $query: {"id": 5000 }, $hint: { "id":1 }}) |
使用鍵列id的索引查詢id=5000的結果 |
db.tab.find({"id": 5000 }).snapshot() db.tab.find({"id": 5000 })._addSpecial( "$snapshot", true ) db.tab.find({ $query: {"id": 5000 }, $snapshot: true }) |
使用快照的查詢id=5000的結果 |
db.tab.find({"id": 5000 }).hint({"id":1}).explain() db.tab.find({"id": 5000})._addSpecial("$explain",1) db.tab.find({ $query: {"id": 5000 }, $hint: { "id":1 }, $explain: 1}) |
查看執行計劃信息 |
索引邊界設置 |
|
db.tab.find({"id": 5000 }).max({ "id":5005}) db.tab.find({ $query:{"id": 5000 },$max:{ "id": 5005}}) db.tab.find({"id": 5000 })._addSpecial("$max",{"id": 5005})
db.tab.find({"id": 5000 }).min({ "id":5000}).max({ "id":5005}).explain() db.tab.find({ $query:{"id": 5000 },$max:{ "id": 5005},$min:{ "id": 5000}}) db.tab.find({"id": 5000 })._addSpecial("$min",{"id": 5000})._addSpecial("$max",{"id": 5005}) |
摘取了這了的一個總結:http://www.w3cschool.cc/mongodb/mongodb-indexing.html
Parameter |
Type |
Description |
background |
Boolean |
建索引過程會阻塞其它數據庫操做,background可指定之後臺方式建立索引,即增長 "background" 可選參數。 "background" 默認值爲false。 |
unique |
Boolean |
創建的索引是否惟一。指定爲true建立惟一索引。默認值爲false. |
name |
string |
索引的名稱。若是未指定,MongoDB的經過鏈接索引的字段名和排序順序生成一個索引名稱。 |
dropDups |
Boolean |
在創建惟一索引時是否刪除重複記錄,指定 true 建立惟一索引。默認值爲 false. |
sparse |
Boolean |
對文檔中不存在的字段數據不啓用索引;這個參數須要特別注意,若是設置爲true的話,在索引字段中不會查詢出不包含對應字段的文檔.。默認值爲 false. |
expireAfterSeconds |
integer |
指定一個以秒爲單位的數值,完成 TTL設定,設定集合的生存時間。 |
v |
index version |
索引的版本號。默認的索引版本取決於mongod建立索引時運行的版本。 |
weights |
document |
索引權重值,數值在 1 到 99,999 之間,表示該索引相對於其餘索引字段的得分權重。 |
default_language |
string |
對於文本索引,該參數決定了停用詞及詞幹和詞器的規則的列表。 默認爲英語 |
language_override |
string |
對於文本索引,該參數指定了包含在文檔中的字段名,語言覆蓋默認的language,默認值爲 language. |