MongoDB入門之索引(一)
索引 就像書的目錄,如果查找某內容在沒有目錄的幫助下,只能全篇查找翻閱,這導致效率非常的低下;如果在借助目錄情況下,就能很快的定位具體內容所在區域,效率會直線提高。
首先打開命令行,輸入 mongo 。默認mongodb會連接名為 test 的數據庫。
? ~ mongo MongoDB shell version: 2.4.9 connecting to: test > show collections >
可以使用 show collections/tables 查看數據庫為空。
然后在mongodb命令行終端執行如下代碼
> for(var i=0;i<100000;i++) { ... db.users.insert({username:'user'+i}) ... } > show collections system.indexes users >
再查看數據庫發現多了 system.indexes 和 users 兩個表,前者即所謂的 索引 ,后者為新建的數據庫表。
這樣 user 表中即有了 10萬 條數據。
> db.users.find() { "_id" : ObjectId("5694d5da8fad9e319c5b43e4"), "username" : "user0" } { "_id" : ObjectId("5694d5da8fad9e319c5b43e5"), "username" : "user1" } { "_id" : ObjectId("5694d5da8fad9e319c5b43e6"), "username" : "user2" } { "_id" : ObjectId("5694d5da8fad9e319c5b43e7"), "username" : "user3" } { "_id" : ObjectId("5694d5da8fad9e319c5b43e8"), "username" : "user4" } { "_id" : ObjectId("5694d5da8fad9e319c5b43e9"), "username" : "user5" }
現在需要查找其中任意一條數據,比如
> db.users.find({username: 'user1234'}) { "_id" : ObjectId("5694d5db8fad9e319c5b48b6"), "username" : "user1234" }
發現這條數據成功找到,但需要了解詳細信息,需要加上 explain 方法
> db.users.find({username: 'user1234'}).explain() { "cursor" : "BasicCursor", "isMultiKey" : false, "n" : 1, "nscannedObjects" : 100000, "nscanned" : 100000, "nscannedObjectsAllPlans" : 100000, "nscannedAllPlans" : 100000, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 0, "nChunkSkips" : 0, "millis" : 30, "indexBounds" : { }, "server" : "root:27017" }
參數很多,目前我們只關注其中的 "nscanned" : 100000 和 "millis" : 30 這兩項。
nscanned 表示mongodb在完成這個查詢過程中掃描的文檔總數。可以發現,集合中的每個文檔都被掃描了,并且總時間為30毫秒。
如果數據有1000萬個,如果每次查詢文檔都被遍歷一遍,時間也是相當可觀。
對于此類查詢,索引是一個非常好的解決方案。
> db.users.ensureIndex({"username": 1})
然后再查找 user1234
> db.users.ensureIndex({"username": 1}) > db.users.find({username: 'user1234'}).explain() { "cursor" : "BtreeCursor username_1", "isMultiKey" : false, "n" : 1, "nscannedObjects" : 1, "nscanned" : 1, "nscannedObjectsAllPlans" : 1, "nscannedAllPlans" : 1, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 0, "nChunkSkips" : 0, "millis" : 0, "indexBounds" : { "username" : [ [ "user1234", "user1234" ] ] }, "server" : "root:27017" }
的確有點不可思議,查詢在瞬間完成,因為通過索引只查找了一條數據,而不是100000條。
當然使用索引是也是有代價的:對于添加的每一條索引,每次寫操作(插入、更新、刪除)都將耗費更多的時間。這是因為,當數據發生變化時,不僅要更新文檔,還要更新級集合上的所有索引。因此,mongodb限制每個集合最多有64個索引。通常,在一個特定的集合上,不應該擁有兩個以上的索引。
小技巧
如果一個非常通用的查詢,或者這個查詢造成了性能瓶頸,那么在某字段(比如 username )建立索引是非常好的選擇。但只是給管理員用的查詢(不太在意查詢耗費時間),就不該對這個字段建立索引。