mongodb查詢計劃(explain)分析
環境
mongodb:3.4
robomongo:1.0.RC1
explain 返回的資料
執行的語句:
db.urlcontents.find({ir_urltitle:{$regex:"科技"}, ir_groupname:"產業熱點" }).sort({ir_urltime:-1}).explain("queryPlanner")
結果為:
{
"cursor" : "BtreeCursor ir_groupname_1_ir_urltime_-1_ir_urltitle_1 multi"-索引名,
"isMultiKey" : false --- 是否使用多鍵索引 ,
"n" : 39 --- 返回的文件數量,
"nscannedObjects" : 39 --- Mongodb按照索引指標去磁碟上查詢實際文件次數,
"nscanned" : 3103 --- 查詢過的索引條目數,
"nscannedObjectsAllPlans" : 3144,
"nscannedAllPlans" : 12424,
"scanAndOrder" : false --- 是否在記憶體中排序,
"indexOnly" : false --- 是否使用了索引覆蓋,
"nYields" : 0 --- 為了讓寫入請求能夠順利執行,本次查詢暫停的次數 ,
"nChunkSkips" : 0,
"millis" : 36 --- 查詢計劃花費的總時間,
"indexBounds" : {
"ir_groupname" : [
[
"產業熱點",
"產業熱點"
]
],
"ir_urltime" : [
[
{
"$maxElement" : 1
},
{
"$minElement" : 1
}
]
],
"ir_urltitle" : [
[
"",
{}
],
[
/科技/,
/科技/
]
]
},
"server" : "10-10-114-219:27018"
}
覆蓋索引 (indexOnly:true)
覆蓋索引就是:當一個索引包含使用者請求的所有欄位,可以認為這個索引覆蓋了本次查詢。
所以在實際中,我們應該優先使用覆蓋索引,而不是去獲取實際的文件。這樣可以保證工作集比較小,尤其與右平衡索引一起使用時。 ——《Mongodb權威指南》
由於mongodb預設返回的欄位中包含_id
欄位,所以最好使用投射
來指定不要返回_id
。
如果一個查詢使用的是覆蓋索引,那麼執行explain()
時,indexOnly
欄位的值為true
。
唯一索引
唯一索引可以確保集合的每一個文件的指定鍵都有唯一值。例如,如果想保證不同文件的username
鍵擁有不同的值,建立一個唯一索引就好了:
>db.users.ensureIndex({"username":1},{"unique":true})
如果試圖向上面的集合中插入如下文件:
>db.users.insert({username:"bob"})
>db.users.insert({username:"bob"})
會報錯:E11000 duplicate key error index : test.users.$username_1 dup key :{:”bob”}
系統自動建立的_id
就是唯一索引,這個唯一索引是不能被刪除的,其他唯一索引可以刪除。
複合唯一索引
在上面的基礎上,建立多個鍵的所以即可。
比如:
{username:1, age:1}
稀疏索引
>db.test.ensureIndex({email:1},{unique:true, sparse:true})
上面的意思是:建立了一個可選的唯一索引,也就是說,email
這個欄位可以沒有,如果有,則必須是唯一的,不能重複。而上面唯一索引,即便欄位為null或不存在,也不允許重複出現。sparse
選項是用來建立稀疏索引的。
注意:
稀疏索引不必是唯一的。只要去掉unique
選項,就可以建立一個非唯一的稀疏索引。
零碎知識
一個查詢執行一個索引
mongodb查詢一般情況下,是一次查詢只能使用一個索引,但是$or
是個例外:
假設我們建立了所以{x:1}
和索引{y:1}
db.foo.find({"$or":[{'x':123},{"y":456}]})
這裡執行兩個索引,因為Mongodb
是執行兩次後查詢後,把結果合併到一起的。
mongodb索引管理
mongodb索引統一在system.indexes
集合中管理。
這個集合只能通過ensureIndex
和dropIndexes
來操作。
指定索引名
如果索引包含兩個以上的鍵時,指定索引名稱會更好看些。
>db.foo.ensureIndex({a:1,b:1,c:1,d:1},{"name":"自己取個名字"})
可以呼叫getLastError
方法來檢視索引是否建立成功。
查詢索引資訊
db.people.getIndexes()
刪除索引
db.people.dropIndex("x_1_y_1")
{"nIndexesWas":3, "ok":1}
索引資訊裡的name
欄位就是該索引的唯一標識
建立索引,後臺執行
db.people.ensureIndex({x:1,y:1},{background:1})