MongoDB 索引創(chuàng)建和查詢優(yōu)化的方法
2.1 批量插入數(shù)據(jù)
單條數(shù)據(jù)插入
db.collection.insertOne()
多條數(shù)據(jù)插入
db.collection.insertMany()
db.inventory.insertMany( [ { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" }, { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" }, { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" }, { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" }, { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" } ]);
插入數(shù)據(jù)
use testdb for(var i =1; i<10; i++) db.users.insert({id:i,name: "zhangsan"+i,age: 100+i})
2.2 查詢選擇器
2.2.1 常規(guī)查詢方式
最簡單的查詢語句為:db.customers.find(),按照插入的順序返回前20個文檔,如果 記錄總數(shù)比20大,則我們可以通過命令“it”獲取更多文檔。 > db.users.find({id:9}) 精確匹配選擇器,返回包含鍵值對id:9的文檔。 > db.users.find({name:"xiaoming",age:101}) 精確匹配選擇器,但查詢條件是要返回同時匹配鍵值對{name:"xiaoming",age:101}的文檔。 > db.users.find({age:{$lt:102}}) $lt表示的是小于 > db.users.find({age:{$lte:102}}) $lte表示的小于或等于 > db.users.find({age:{$gt:105}}) $gt表示的是大于 > db.users.find({age:{$gte:105}}) $gte表示的是大于或等于 > db.users.find({age:{$lt:120,$gte:105}}) 范圍選擇器,age:{$lt:120,$gte:119}表示的是小于120,大于或等于119 > db.users.find({id:{$in:[1,2]}}) 表示返回key的值在某些value范圍內 > db.users.find({id:{$nin:[1,2]}}) $nin表示返回key的值不在某些value范圍內,$nin是一種比較低效的査詢選擇器,它會進行全表掃描,因此最好不要單獨使用$nin > db.users.find({id:{$ne:1}}) $ne表示不等于。單獨使用$ne,它也不會利用索引的優(yōu)勢,反而會進行全表掃描,我們最好與其他查詢選擇器配合使用。 > db.users.find({$or:[{id:11},{age:109}] }) $or表示或運算的選擇器,主要用于對兩個不同key對應的文檔進行連接。 > db.users.find({$and:[{id:1},{age:109}]}) $and表示與運算的選擇器,對于兩個不同的key,要同時滿足條件。 > db.users.find({id:{$exists:ture}}) $exists與關系數(shù)據(jù)庫中的exists不一樣,因為MongoDB的表結構不是固定的,有的時候需要返回包含有某個字段的所有記錄或者不包含某個字段的所有記錄。
2.2.2 索引和查詢優(yōu)化
索引是個與數(shù)據(jù)存儲和査詢相關的古老話題,目的只有一個:“提高數(shù)據(jù)獲取的性能”。我們知道一本書的前面幾頁肯定會有一個目錄,這個目錄式的索引能使我們快速査詢想看的內容。索引保存在哪里,是個什么樣的數(shù)據(jù)結構,計算機領域的索引無外乎也是這兩個主題。
數(shù)據(jù)庫保存記錄的機制是建立在文件系統(tǒng)上的,索引也是以文件的形式存儲在磁盤上,在數(shù)據(jù)庫中用到的最多的索引結構就是B樹。盡管索引在數(shù)據(jù)庫領域是不可缺少的,但是對一個表建立過多的索引也會帶來一些問題,索引的建立要花費系統(tǒng)時間,同時索引文件也會占用磁盤空間。
**索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB在讀取數(shù)據(jù)時必須掃描集合中的每個文件并選取那些符合查詢條件的記錄。**掃描全集合的查詢效率是非常低的,特別在處理大量的數(shù)據(jù)時,查詢可以要花費幾十秒甚至幾分鐘,這對網站的性能是非常致命的。
索引是特殊的數(shù)據(jù)結構,索引存儲在一個易于遍歷讀取的數(shù)據(jù)集合中,索引是對數(shù)據(jù)庫表中一列或多列的值進行排序的一種結構。
MongoDB索引的數(shù)據(jù)結構也是B+樹,它能存儲一小部分集合的數(shù)據(jù),具體來說就是存儲集合中建有索引的一個或多個字段的值,而且按照值的升序或降序排列。對于一個查詢來說,如果存在合適的索引,MongoDB能夠利用這個索引減少文檔的掃描數(shù)量。
如圖所示查詢低于30歲的用戶,不用去掃描全部文檔,通過索引快速返回結果,這樣查詢的效率是很高的。
單字段索引
MongoDB默認為所有集合都創(chuàng)建了一個_id字段的單字段索引,而且這個索引是唯一的,不能被刪除,_id字段作為一個集合的主鍵,值是唯一的,對于一個集合來說,也可以在其他字段上創(chuàng)建單字段的唯一索引。
創(chuàng)建單一鍵索引:db.collection.createIndex( { : } ),其中 是你要創(chuàng)建索引的字段名, 是索引類型,例如:1(升序)或 -1(降序)。
插入數(shù)據(jù)
for(var i = 1;i < 10;i++) db.custoners.insert({name:"zhangsan"+i,province:"liaoning"}) for(var i = 1;i < 10;i++) db.customers.insert({name:"lisi"+i,province:"fujian"}) for(var i = 1;i < 10;i++) db.customers.insert({name:"niuer"+i,province:"guangdong"}) for(var i = 1;i < 10;i++) db.customers.insert({name:"wangwu"+i,province:"Hunan"}) for(var i = 1;i < 10;i++) db.customers.insert({name:"liyi"+i,province:"Sichuan"})
創(chuàng)建索引
建立單字段唯一索引或者去掉{unique:true}選項就是一個普通的單字段索引
db.customers.createIndex({name:1},{unique:true})
1表示升序創(chuàng)建索引,-1表示降序創(chuàng)建索引。
通過explain查看執(zhí)行計劃
MongoDB中的explain()方法用于顯示查詢執(zhí)行計劃,它可以幫助我們了解MongoDB如何執(zhí)行一個查詢。
執(zhí)行explain()方法后,MongoDB將返回一個對象,該對象描述了查詢執(zhí)行的過程,包括查詢的階段、輸入輸出、使用的索引等信息。
這個對象通常包含以下字段:
- stages:查詢執(zhí)行的階段列表,每個階段描述了查詢的一部分執(zhí)行過程。
- input:查詢輸入的文檔數(shù)量。
- output:查詢輸出的文檔數(shù)量。
- millis:查詢執(zhí)行的時間(毫秒)。
- executionStats:更詳細的執(zhí)行統(tǒng)計信息。
其中,stages字段是最重要的,它描述了查詢從開始到結束的所有階段。每個階段都有一個type字段,描述了這個階段的類型,比如:
- COLLSCAN:掃描整個集合。
- IXSCAN:掃描索引。
- SHARD_MERGE:合并從多個分片返回的結果。
通過查看stages字段,我們可以了解查詢使用了哪些索引,是否有更好的優(yōu)化方案等。
需要注意的是,explain()方法返回的結果包含了大量的詳細信息,對于普通用戶來說可能比較難以理解。通常我們只需要關注stages字段,以及其中的type值為IXSCAN的階段,因為這是查詢執(zhí)行的關鍵階段。
沒走索引查詢,查詢使用了COLLSCAN階段掃描了整個集合,但是并沒有使用到索引。
命中索引進行查詢
復合索引
創(chuàng)建復合索引:db.collection.createIndex( { : , : } ),其中 和 是你要創(chuàng)建索引的字段名, 和 是索引類型,
例如:1(升序)或 -1(降序)。
請注意,創(chuàng)建索引可能需要一些時間,具體取決于你的數(shù)據(jù)量及系統(tǒng)性能。同時,創(chuàng)建過多的索引可能會對寫入性能產生負面影響,因此需要謹慎考慮。
> db.customers.find({"name" : "liyi6", "province" : "Sichuan"}).explain() { "explainVersion" : "1", "queryPlanner" : { "namespace" : "sample_mflix.customers", "indexFilterSet" : false, "parsedQuery" : { "$and" : [ { "name" : { "$eq" : "liyi6" } }, { "province" : { "$eq" : "Sichuan" } } ] }, "queryHash" : "AE1EB7A5", "planCacheKey" : "C0AA3338", "maxIndexedOrSolutionsReached" : false, "maxIndexedAndSolutionsReached" : false, "maxScansToExplodeReached" : false, "winningPlan" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "name" : 1, "province" : 1 }, "indexName" : "name_1_province_1", "isMultiKey" : false, "multiKeyPaths" : { "name" : [ ], "province" : [ ] }, "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "name" : [ "[\"liyi6\", \"liyi6\"]" ], "province" : [ "[\"Sichuan\", \"Sichuan\"]" ] } } }, "rejectedPlans" : [ ] }, "command" : { "find" : "customers", "filter" : { "name" : "liyi6", "province" : "Sichuan" }, "$db" : "sample_mflix" }, "serverInfo" : { "host" : "13727b89dec5", "port" : 27017, "version" : "5.0.5", "gitVersion" : "d65fd89df3fc039b5c55933c0f71d647a54510ae" }, "serverParameters" : { "internalQueryFacetBufferSizeBytes" : 104857600, "internalQueryFacetMaxOutputDocSizeBytes" : 104857600, "internalLookupStageIntermediateDocumentMaxSizeBytes" : 104857600, "internalDocumentSourceGroupMaxMemoryBytes" : 104857600, "internalQueryMaxBlockingSortMemoryUsageBytes" : 104857600, "internalQueryProhibitBlockingMergeOnMongoS" : 0, "internalQueryMaxAddToSetBytes" : 104857600, "internalDocumentSourceSetWindowFieldsMaxMemoryBytes" : 104857600 }, "ok" : 1 }
數(shù)組的多鍵索引
注意,創(chuàng)建索引可能需要一些時間,具體取決于你的數(shù)據(jù)量和系統(tǒng)性能。同時,創(chuàng)建過多的索引可能會對寫入性能產生負面影響,因此需要謹慎考慮。
tags 的數(shù)組字段為例,展示多鍵索
> for(var i = 1;i < 10;i++) db.ccustomers.insert({name:"liyi"+i,"tags": ["sports", "music", "movies"]}) WriteResult({ "nInserted" : 1 }) > for(var i = 1;i < 10;i++) db.ccustomers.insert({name:"liyao"+i,"tags": ["sports", "movies","games","read"]}) WriteResult({ "nInserted" : 1 }) > for(var i = 1;i < 10;i++) db.ccustomers.insert({name:"lisi"+i,"tags": ["sports", "music", "movies"]}) WriteResult({ "nInserted" : 1 }) > for(var i = 1;i < 10;i++) db.ccustomers.insert({name:"liyiyi"+i,"tags": ["sports", "movies","write"]}) WriteResult({ "nInserted" : 1 }) > db.ccustomers.createIndex({"tags":1}) { "numIndexesBefore" : 1, "numIndexesAfter" : 2, "createdCollectionAutomatically" : false, "ok" : 1 }
explain
查詢結果
查詢優(yōu)化
MongoDB查詢優(yōu)化的方法主要有以下幾點:
- 用合適的索引:索引是提高查詢性能的關鍵。MongoDB支持多種索引類型,如單一鍵索引、復合索引、文本索引、地理空間索引等。在設計數(shù)據(jù)庫時,應根據(jù)數(shù)據(jù)的特性和查詢需求選擇合適的索引類型。同時,也要注意索引的使用,盡量使用已經創(chuàng)建的索引,避免全集合掃描。
- 優(yōu)化查詢語句:查詢語句的設計也會影響查詢性能。應盡量避免使用不等于操作符、模運算符等導致全集合掃描的操作符。同時,應使用投影查詢,減少返回的字段,減少數(shù)據(jù)傳輸和處理的開銷。
- 批量操作:批量操作可以減少IO操作次數(shù),提高性能。例如批量插入、批量更新、批量刪除等。
- 使用緩存:使用緩存可以避免重復查詢,提高查詢性能。
- 優(yōu)化數(shù)據(jù)結構:數(shù)據(jù)結構的設計也會影響查詢性能。應盡量選擇合適的數(shù)據(jù)類型,避免使用嵌套文檔和數(shù)組,提高查詢效率。
- 調整系統(tǒng)參數(shù):根據(jù)系統(tǒng)性能和硬件配置調整MongoDB的配置參數(shù),例如內存、磁盤、網絡等參數(shù)。
- 使用分析工具:使用MongoDB提供的分析工具,如explain()、profile()等,可以了解查詢性能,找出優(yōu)化點。
位慢查詢的方法是打開數(shù)據(jù)庫的監(jiān)視功能,它默認是關閉的,我們可以通過下面的命令打開。
db.setProfilingLevel(level,[ slowms])
參數(shù):
level是監(jiān)視級別。
值為0表示關閉數(shù)據(jù)庫的監(jiān)視功能
值為1表示只記錄慢查詢
值為2表示記錄所有的操作
slowms為可選參數(shù),設定慢查詢的閾值。
所有監(jiān)視的結果都將保存到一個特殊的集合system.profile中。
> db.setProfilingLevel(2) { "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 } > db.system.profile.find()
實操記錄:
一個走索引和沒有走索引的查詢
打開查看查詢記錄:
2.3 總結
MongoDB可以在一個集合上建立一個或多個索引,而且必須為在字段_id建立一個索引,建索引的目的與關系數(shù)據(jù)庫一樣,就是為了提高對數(shù)據(jù)庫的查詢效率;
一旦索引創(chuàng)建好,MongoDB會自動地根據(jù)數(shù)據(jù)的變化維護索引,如果索引太大而不能全部保存在內存中,將被移到磁盤文件上,這樣會影響查詢性能,因此要時刻監(jiān)控索引的大小,保證合適的索引在內存中;
監(jiān)控一個查詢是否用到索引,可以在查詢語句后用explain命令或profile()方式進行監(jiān)控。并不是所有的字段都要建立索引,我們應該根據(jù)自己業(yè)務所涉及的查詢,建立合適的索引;
如果系統(tǒng)有大量的寫操作,由于需要維護索引的變化,會導致系統(tǒng)性能降低。我們在對大數(shù)據(jù)建立索引時最好在后臺進行,否則會導致數(shù)據(jù)庫停止響應。要注意雖然我們在某些字段上建了索引,但是查詢時可能用不上索引,如使用 n e 和 ne和 ne和nin表達式等。
到此這篇關于MongoDB 索引創(chuàng)建和查詢優(yōu)化的文章就介紹到這了,更多相關MongoDB 索引和查詢內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
MongoDB數(shù)據(jù)庫查詢性能提高40倍的經歷分享
大家在使用 MongoDB 的時候有沒有碰到過性能問題呢?下面這篇文章主要給大家分享了MongoDB數(shù)據(jù)庫查詢性能提高40倍的經歷,需要的朋友可以參考借鑒,下面來一起看看吧。2017-02-02window平臺安裝MongoDB數(shù)據(jù)庫圖文詳解
本篇文章主要介紹了window平臺安裝MongoDB數(shù)據(jù)庫圖文詳解,主要介紹window下面安裝mogod的步驟和使用細節(jié)。感興趣的小伙伴們可以參考一下。2016-11-11MongoDB在系統(tǒng)數(shù)據(jù)庫local中無法創(chuàng)建用戶的解決辦法
這篇文章主要給大家介紹了關于MongoDB在系統(tǒng)數(shù)據(jù)庫local中無法創(chuàng)建用戶的解決辦法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-11-11