<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                今天分享下mongodb中關于索引的基本操作,我們日常做開發都避免不了要對程序進行性能優化,而程序的操作無非就是CURD,通常我們又會花費50%的時間在R上面,因為Read操作對用戶來說是非常敏感的,處理不好就會被人唾棄。 從算法上來說有5種經典的查找,具體的可以參見我的算法速成系列,這其中就包括我們今天所說的“索引查找”,如果大家對sqlserver比較了解的話,相信索引查找能給我們帶來什么樣的性能提升吧。 <!--more--> 我們首先插入10w數據,上程序說話: ``` db.person.drop();//刪除person集合 //創建10W條數據 for(var i=0; i< 100000; i++){ db.user.insert({"name":"hxj"+i, "age" : i}); } > db.user.count(); 100000 ``` 已經有10W條數據了。 ## 性能分析函數(explain) 好了,數據已經插入成功,既然我們要做分析,肯定要有分析的工具,幸好mongodb中給我們提供了一個關鍵字叫做“explain",那么怎么用呢? 還是看程序,注意,這里的name字段沒有建立任何索引,這里我就查詢一個“name10000”的姓名。 ``` > db.user.find({"name" : "hxj"+10000}); { "_id" : ObjectId("55935a673cb05382291d31a0"), "name" : "hxj10000", "age" : 10000 } > db.user.find({"name" : "hxj"+10000}).explain(); { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "test.user", "indexFilterSet" : false, "parsedQuery" : { "name" : { "$eq" : "hxj10000" } }, "winningPlan" : { "stage" : "COLLSCAN", "filter" : { "name" : { "$eq" : "hxj10000" } }, "direction" : "forward" }, "rejectedPlans" : [ ] }, "serverInfo" : { "host" : "YJC-PC", "port" : 27017, "version" : "3.0.4", "gitVersion" : "0481c958daeb2969800511e7475dc66986fa9ed5" }, "ok" : 1 } ``` 其中: ``` "stage" : "COLLSCAN", ``` `stage` 是`COLLSCAN`,說明沒有走索引,走索引的話會顯示`IXSCAN`。 基于mongo3.0,和2.x的版本有些地方會不大一樣。 舊版的話,會有幾個Key可以看下: `cursor`: 如果出現的是`BasicCursor`,就是說這里的查找采用的是“表掃描”,也就是順序查找,很悲催啊。 `nscanned`:表示數據庫瀏覽了多少個文檔。 `n`: 最終返回了多少個文檔。 `millis`:總共耗時多少毫秒。 ## 建立索引(ensureIndex) 在10w條這么簡單的集合中查找一個文檔要114毫秒有一點點讓人不能接收(2.x版本),好,那么我們該如何優化呢?mongodb中給我們帶來了索引查找,看看能不能讓我們的查詢一飛沖天..... ``` > db.user.ensureIndex({"name":1}); { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 } > db.user.find({"name" : "hxj"+10000}).explain(); { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "test.user", "indexFilterSet" : false, "parsedQuery" : { "name" : { "$eq" : "hxj10000" } }, "winningPlan" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "name" : 1 }, "indexName" : "name_1", "isMultiKey" : false, "direction" : "forward", "indexBounds" : { "name" : [ "[\"hxj10000\", \"hxj10000\"]" ] } } }, "rejectedPlans" : [ ] }, "serverInfo" : { "host" : "YJC-PC", "port" : 27017, "version" : "3.0.4", "gitVersion" : "0481c958daeb2969800511e7475dc66986fa9ed5" }, "ok" : 1 } ``` 這里我們使用了ensureIndex在name上建立了索引。 `1`:表示按照name進行升序,`-1`:表示按照name進行降序。 這回`stage` 是`FETCH`。 如果是2.x版本,會有這些信息: `cursor`: 如果是`BtreeCursor`,這么牛X,mongodb采用B樹的結構來存放索引,索引名為后面的“name_1"。 `nscanned`:表示數據庫瀏覽了多少個文檔。 `n`: 最終返回了多少個文檔。 `millis`:總共耗時多少毫秒。 通過這個例子相信大家對索引也有了感官方面的認識了吧。 ## 唯一索引 和sqlserver一樣都可以建立唯一索引,重復的鍵值自然就不能插入,在mongodb中的使用方法是: ``` db.user.ensureIndex({"name":1},{"unique":true}) /*刪除所有數據,發現刪除不了*/ > db.user.remove() 2015-07-01T11:29:38.579+0800 E QUERY Error: remove needs a query at Error (<anonymous>) at DBCollection._parseRemove (src/mongo/shell/collection.js:305:32) at DBCollection.remove (src/mongo/shell/collection.js:328:23) at (shell):1:9 at src/mongo/shell/collection.js:305 /*刪除所有數據*/ > db.user.remove({}) WriteResult({ "nRemoved" : 100000 }) > db.user.ensureIndex({"name":1}, {"unique": true}); { "createdCollectionAutomatically" : false, "numIndexesBefore" : 2, "errmsg" : "exception: Index with name: name_1 already exists with different options", "code" : 85, "ok" : 0 } > db.user.count() 0 /*清空集合里數據*/ > db.user.drop() true > db.user.ensureIndex({"name":1}, {"unique": true}); { "createdCollectionAutomatically" : true, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 } > db.user.insert({"name":"yjc", "age": 22}); WriteResult({ "nInserted" : 1 }) > db.user.insert({"name":"yjc", "age": 23}); WriteResult({ "nInserted" : 0, "writeError" : { "code" : 11000, "errmsg" : "E11000 duplicate key error index: test.user.$name_1 dup key: { : \"yjc\" }" } }) ``` ## 組合索引 有時候我們的查詢不是單條件的,可能是多條件,比如查找出生在‘1989-3-2’名字叫‘jack’的同學,那么我們可以建立“姓名”和"生日“的聯合索引來加速查詢。 ``` > db.user.insert({"name" : "hxc", "birthday" : "1989-2-2"}); WriteResult({ "nInserted" : 1 }) > db.user.insert({"name" : "jack", "birthday" : "1989-3-2"}); WriteResult({ "nInserted" : 1 }) > db.user.insert({"name" : "joe", "birthday" : "1989-2-22"}); WriteResult({ "nInserted" : 1 }) > db.user.insert({"name" : "mary", "birthday" : "1989-3-12"}); WriteResult({ "nInserted" : 1 }) > db.user.insert({"name" : "jr", "birthday" : "1989-3-2"}); WriteResult({ "nInserted" : 1 }) > db.user.ensureIndex({"name":1, "birthday":1}) { "createdCollectionAutomatically" : false, "numIndexesBefore" : 2, "numIndexesAfter" : 3, "ok" : 1 } > db.user.ensureIndex({"birthday":1, "name":1}) { "createdCollectionAutomatically" : false, "numIndexesBefore" : 3, "numIndexesAfter" : 4, "ok" : 1 } ``` 看到上面,大家或者也知道name跟birthday的不同,建立的索引也不同,升序和降序的順序不同都會產生不同的索引,那么我們可以用getindexes來查看下person集合中到底生成了那些索引。 ``` > db.user.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.user" }, { "v" : 1, "unique" : true, "key" : { "name" : 1 }, "name" : "name_1", "ns" : "test.user" }, { "v" : 1, "key" : { "name" : 1, "birthday" : 1 }, "name" : "name_1_birthday_1", "ns" : "test.user" }, { "v" : 1, "key" : { "birthday" : 1, "name" : 1 }, "name" : "birthday_1_name_1", "ns" : "test.user" } ] ``` 此時我們肯定很好奇,到底查詢優化器會使用哪個查詢作為操作: ``` > db.user.find({"name":"jack", "birthday":"1989-3-2"}).explain(); { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "test.user", "indexFilterSet" : false, "parsedQuery" : { "$and" : [ { "birthday" : { "$eq" : "1989-3-2" } }, { "name" : { "$eq" : "jack" } } ] }, "winningPlan" : { "stage" : "KEEP_MUTATIONS", "inputStage" : { "stage" : "FETCH", "filter" : { "birthday" : { "$eq" : "1989-3-2" } }, "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "name" : 1 }, "indexName" : "name_1", "isMultiKey" : false, "direction" : "forward", "indexBounds" : { "name" : [ "[\"jack\", \"jack\"]" ] } } } }, "rejectedPlans" : [ ] }, "serverInfo" : { "host" : "YJC-PC", "port" : 27017, "version" : "3.0.4", "gitVersion" : "0481c958daeb2969800511e7475dc66986fa9ed5" }, "ok" : 1 } ``` 看到結果我們要相信查詢優化器,它給我們做出的選擇往往是最優的,因為我們做查詢時,查詢優化器會使用我們建立的這些索引來創建查詢方案,如果某一個先執行完則其他查詢方案被close掉,這種方案會被mongodb保存起來,當然如果非要用自己指定的查詢方案,這也是可以的,在mongodb中給我們提供了hint方法讓我們可以暴力執行。 ``` > db.user.find({"name":"jack", "birthday":"1989-3-2"}).hint({"birthday":1, "name":1}).explain(); { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "test.user", "indexFilterSet" : false, "parsedQuery" : { "$and" : [ { "birthday" : { "$eq" : "1989-3-2" } }, { "name" : { "$eq" : "jack" } } ] }, "winningPlan" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "birthday" : 1, "name" : 1 }, "indexName" : "birthday_1_name_1", "isMultiKey" : false, "direction" : "forward", "indexBounds" : { "birthday" : [ "[\"1989-3-2\", \"1989-3-2\"]" ], "name" : [ "[\"jack\", \"jack\"]" ] } } }, "rejectedPlans" : [ ] }, "serverInfo" : { "host" : "YJC-PC", "port" : 27017, "version" : "3.0.4", "gitVersion" : "0481c958daeb2969800511e7475dc66986fa9ed5" }, "ok" : 1 } ``` ## 刪除索引 可能隨著業務需求的變化,原先建立的索引可能沒有存在的必要了,可能有的人想說沒必要就沒必要唄,但是請記住,索引會降低CUD這三種操作的性能,因為這玩意需要實時維護,所以啥問題都要綜合考慮一下,這里就把剛才建立的索引清空掉來演示一下:dropIndex的使用。 dropIndex()刪除某個索引 dropIndexes()刪除全部索引 先查看索引: ``` > db.user.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.user" }, { "v" : 1, "key" : { "name" : 1, "birthday" : 1 }, "name" : "name_1_birthday_1", "ns" : "test.user" }, { "v" : 1, "key" : { "name" : 1 }, "name" : "name_1", "ns" : "test.user" }, { "v" : 1, "key" : { "name" : 1, "unique" : true }, "name" : "name_1_unique_true", "ns" : "test.user" } ] ``` 刪除普通索引: ``` > db.user.dropIndex("name_1"); { "nIndexesWas" : 4, "ok" : 1 } ``` 刪除全部索引: ``` > db.user.dropIndexes(); { "nIndexesWas" : 3, "msg" : "non-_id indexes dropped for collection", "ok" : 1 } ``` 查看還有什么索引 ``` > db.user.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.user" } ] ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看