1. 程式人生 > >mongodb查詢計劃(explain)分析

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集合中管理。
這個集合只能通過ensureIndexdropIndexes來操作。

指定索引名

如果索引包含兩個以上的鍵時,指定索引名稱會更好看些。

>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})