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個(gè)文檔,如果 記錄總數(shù)比20大,則我們可以通過命令“it”獲取更多文檔。 > db.users.find({id:9}) 精確匹配選擇器,返回包含鍵值對id:9的文檔。 > db.users.find({name:"xiaoming",age:101}) 精確匹配選擇器,但查詢條件是要返回同時(shí)匹配鍵值對{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范圍內(nèi) > db.users.find({id:{$nin:[1,2]}}) $nin表示返回key的值不在某些value范圍內(nèi),$nin是一種比較低效的査詢選擇器,它會進(jìn)行全表掃描,因此最好不要單獨(dú)使用$nin > db.users.find({id:{$ne:1}}) $ne表示不等于。單獨(dú)使用$ne,它也不會利用索引的優(yōu)勢,反而會進(jìn)行全表掃描,我們最好與其他查詢選擇器配合使用。 > db.users.find({$or:[{id:11},{age:109}] }) $or表示或運(yùn)算的選擇器,主要用于對兩個(gè)不同key對應(yīng)的文檔進(jìn)行連接。 > db.users.find({$and:[{id:1},{age:109}]}) $and表示與運(yùn)算的選擇器,對于兩個(gè)不同的key,要同時(shí)滿足條件。 > db.users.find({id:{$exists:ture}}) $exists與關(guān)系數(shù)據(jù)庫中的exists不一樣,因?yàn)镸ongoDB的表結(jié)構(gòu)不是固定的,有的時(shí)候需要返回包含有某個(gè)字段的所有記錄或者不包含某個(gè)字段的所有記錄。
2.2.2 索引和查詢優(yōu)化
索引是個(gè)與數(shù)據(jù)存儲和査詢相關(guān)的古老話題,目的只有一個(gè):“提高數(shù)據(jù)獲取的性能”。我們知道一本書的前面幾頁肯定會有一個(gè)目錄,這個(gè)目錄式的索引能使我們快速査詢想看的內(nèi)容。索引保存在哪里,是個(gè)什么樣的數(shù)據(jù)結(jié)構(gòu),計(jì)算機(jī)領(lǐng)域的索引無外乎也是這兩個(gè)主題。
數(shù)據(jù)庫保存記錄的機(jī)制是建立在文件系統(tǒng)上的,索引也是以文件的形式存儲在磁盤上,在數(shù)據(jù)庫中用到的最多的索引結(jié)構(gòu)就是B樹。盡管索引在數(shù)據(jù)庫領(lǐng)域是不可缺少的,但是對一個(gè)表建立過多的索引也會帶來一些問題,索引的建立要花費(fèi)系統(tǒng)時(shí)間,同時(shí)索引文件也會占用磁盤空間。
**索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB在讀取數(shù)據(jù)時(shí)必須掃描集合中的每個(gè)文件并選取那些符合查詢條件的記錄。**掃描全集合的查詢效率是非常低的,特別在處理大量的數(shù)據(jù)時(shí),查詢可以要花費(fèi)幾十秒甚至幾分鐘,這對網(wǎng)站的性能是非常致命的。
索引是特殊的數(shù)據(jù)結(jié)構(gòu),索引存儲在一個(gè)易于遍歷讀取的數(shù)據(jù)集合中,索引是對數(shù)據(jù)庫表中一列或多列的值進(jìn)行排序的一種結(jié)構(gòu)。
MongoDB索引的數(shù)據(jù)結(jié)構(gòu)也是B+樹,它能存儲一小部分集合的數(shù)據(jù),具體來說就是存儲集合中建有索引的一個(gè)或多個(gè)字段的值,而且按照值的升序或降序排列。對于一個(gè)查詢來說,如果存在合適的索引,MongoDB能夠利用這個(gè)索引減少文檔的掃描數(shù)量。
如圖所示查詢低于30歲的用戶,不用去掃描全部文檔,通過索引快速返回結(jié)果,這樣查詢的效率是很高的。
單字段索引
MongoDB默認(rèn)為所有集合都創(chuàng)建了一個(gè)_id字段的單字段索引,而且這個(gè)索引是唯一的,不能被刪除,_id字段作為一個(gè)集合的主鍵,值是唯一的,對于一個(gè)集合來說,也可以在其他字段上創(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}選項(xiàng)就是一個(gè)普通的單字段索引
db.customers.createIndex({name:1},{unique:true})
1表示升序創(chuàng)建索引,-1表示降序創(chuàng)建索引。
通過explain查看執(zhí)行計(jì)劃
MongoDB中的explain()方法用于顯示查詢執(zhí)行計(jì)劃,它可以幫助我們了解MongoDB如何執(zhí)行一個(gè)查詢。
執(zhí)行explain()方法后,MongoDB將返回一個(gè)對象,該對象描述了查詢執(zhí)行的過程,包括查詢的階段、輸入輸出、使用的索引等信息。
這個(gè)對象通常包含以下字段:
- stages:查詢執(zhí)行的階段列表,每個(gè)階段描述了查詢的一部分執(zhí)行過程。
- input:查詢輸入的文檔數(shù)量。
- output:查詢輸出的文檔數(shù)量。
- millis:查詢執(zhí)行的時(shí)間(毫秒)。
- executionStats:更詳細(xì)的執(zhí)行統(tǒng)計(jì)信息。
其中,stages字段是最重要的,它描述了查詢從開始到結(jié)束的所有階段。每個(gè)階段都有一個(gè)type字段,描述了這個(gè)階段的類型,比如:
- COLLSCAN:掃描整個(gè)集合。
- IXSCAN:掃描索引。
- SHARD_MERGE:合并從多個(gè)分片返回的結(jié)果。
通過查看stages字段,我們可以了解查詢使用了哪些索引,是否有更好的優(yōu)化方案等。
需要注意的是,explain()方法返回的結(jié)果包含了大量的詳細(xì)信息,對于普通用戶來說可能比較難以理解。通常我們只需要關(guān)注stages字段,以及其中的type值為IXSCAN的階段,因?yàn)檫@是查詢執(zhí)行的關(guān)鍵階段。
沒走索引查詢,查詢使用了COLLSCAN階段掃描了整個(gè)集合,但是并沒有使用到索引。
命中索引進(jìn)行查詢
復(fù)合索引
創(chuàng)建復(fù)合索引:db.collection.createIndex( { : , : } ),其中 和 是你要創(chuàng)建索引的字段名, 和 是索引類型,
例如:1(升序)或 -1(降序)。
請注意,創(chuàng)建索引可能需要一些時(shí)間,具體取決于你的數(shù)據(jù)量及系統(tǒng)性能。同時(shí),創(chuàng)建過多的索引可能會對寫入性能產(chǎn)生負(fù)面影響,因此需要謹(jǐn)慎考慮。
> 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í)間,具體取決于你的數(shù)據(jù)量和系統(tǒng)性能。同時(shí),創(chuàng)建過多的索引可能會對寫入性能產(chǎn)生負(fù)面影響,因此需要謹(jǐn)慎考慮。
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
查詢結(jié)果
查詢優(yōu)化
MongoDB查詢優(yōu)化的方法主要有以下幾點(diǎn):
- 用合適的索引:索引是提高查詢性能的關(guān)鍵。MongoDB支持多種索引類型,如單一鍵索引、復(fù)合索引、文本索引、地理空間索引等。在設(shè)計(jì)數(shù)據(jù)庫時(shí),應(yīng)根據(jù)數(shù)據(jù)的特性和查詢需求選擇合適的索引類型。同時(shí),也要注意索引的使用,盡量使用已經(jīng)創(chuàng)建的索引,避免全集合掃描。
- 優(yōu)化查詢語句:查詢語句的設(shè)計(jì)也會影響查詢性能。應(yīng)盡量避免使用不等于操作符、模運(yùn)算符等導(dǎo)致全集合掃描的操作符。同時(shí),應(yīng)使用投影查詢,減少返回的字段,減少數(shù)據(jù)傳輸和處理的開銷。
- 批量操作:批量操作可以減少IO操作次數(shù),提高性能。例如批量插入、批量更新、批量刪除等。
- 使用緩存:使用緩存可以避免重復(fù)查詢,提高查詢性能。
- 優(yōu)化數(shù)據(jù)結(jié)構(gòu):數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)也會影響查詢性能。應(yīng)盡量選擇合適的數(shù)據(jù)類型,避免使用嵌套文檔和數(shù)組,提高查詢效率。
- 調(diào)整系統(tǒng)參數(shù):根據(jù)系統(tǒng)性能和硬件配置調(diào)整MongoDB的配置參數(shù),例如內(nèi)存、磁盤、網(wǎng)絡(luò)等參數(shù)。
- 使用分析工具:使用MongoDB提供的分析工具,如explain()、profile()等,可以了解查詢性能,找出優(yōu)化點(diǎn)。
位慢查詢的方法是打開數(shù)據(jù)庫的監(jiān)視功能,它默認(rèn)是關(guān)閉的,我們可以通過下面的命令打開。
db.setProfilingLevel(level,[ slowms])
參數(shù):
level是監(jiān)視級別。
值為0表示關(guān)閉數(shù)據(jù)庫的監(jiān)視功能
值為1表示只記錄慢查詢
值為2表示記錄所有的操作
slowms為可選參數(shù),設(shè)定慢查詢的閾值。
所有監(jiān)視的結(jié)果都將保存到一個(gè)特殊的集合system.profile中。
> db.setProfilingLevel(2) { "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 } > db.system.profile.find()
實(shí)操記錄:
一個(gè)走索引和沒有走索引的查詢
打開查看查詢記錄:
2.3 總結(jié)
MongoDB可以在一個(gè)集合上建立一個(gè)或多個(gè)索引,而且必須為在字段_id建立一個(gè)索引,建索引的目的與關(guān)系數(shù)據(jù)庫一樣,就是為了提高對數(shù)據(jù)庫的查詢效率;
一旦索引創(chuàng)建好,MongoDB會自動地根據(jù)數(shù)據(jù)的變化維護(hù)索引,如果索引太大而不能全部保存在內(nèi)存中,將被移到磁盤文件上,這樣會影響查詢性能,因此要時(shí)刻監(jiān)控索引的大小,保證合適的索引在內(nèi)存中;
監(jiān)控一個(gè)查詢是否用到索引,可以在查詢語句后用explain命令或profile()方式進(jìn)行監(jiān)控。并不是所有的字段都要建立索引,我們應(yīng)該根據(jù)自己業(yè)務(wù)所涉及的查詢,建立合適的索引;
如果系統(tǒng)有大量的寫操作,由于需要維護(hù)索引的變化,會導(dǎo)致系統(tǒng)性能降低。我們在對大數(shù)據(jù)建立索引時(shí)最好在后臺進(jìn)行,否則會導(dǎo)致數(shù)據(jù)庫停止響應(yīng)。要注意雖然我們在某些字段上建了索引,但是查詢時(shí)可能用不上索引,如使用 n e 和 ne和 ne和nin表達(dá)式等。
到此這篇關(guān)于MongoDB 索引創(chuàng)建和查詢優(yōu)化的文章就介紹到這了,更多相關(guān)MongoDB 索引和查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MongoDB數(shù)據(jù)庫查詢性能提高40倍的經(jīng)歷分享
大家在使用 MongoDB 的時(shí)候有沒有碰到過性能問題呢?下面這篇文章主要給大家分享了MongoDB數(shù)據(jù)庫查詢性能提高40倍的經(jīng)歷,需要的朋友可以參考借鑒,下面來一起看看吧。2017-02-02Mongodb 3.2.9開啟用戶權(quán)限認(rèn)證問題的步驟詳解
這篇文章主要給大家介紹了關(guān)于Mongodb 3.2.9開啟用戶權(quán)限認(rèn)證問題的詳細(xì)步驟,通過開啟權(quán)限認(rèn)證,會對大家的Mongodb更加保護(hù)的安全些,文中將步驟介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。2017-08-08教大家8天學(xué)通MongoDB——第一天 基礎(chǔ)入門篇
MongoDB是目前非常流行的一種非關(guān)系型數(shù)據(jù)庫(NoSQL),因其操作簡單、完全免費(fèi)、源碼公開等特點(diǎn),受到了IT從業(yè)人員的青睞,并被廣泛部署于實(shí)際的生產(chǎn)環(huán)境中。本文教大家8天學(xué)通MongoDB——第一天 基礎(chǔ)入門篇,感興趣的朋友一起來了解了解吧2015-09-09window平臺安裝MongoDB數(shù)據(jù)庫圖文詳解
本篇文章主要介紹了window平臺安裝MongoDB數(shù)據(jù)庫圖文詳解,主要介紹window下面安裝mogod的步驟和使用細(xì)節(jié)。感興趣的小伙伴們可以參考一下。2016-11-11MongoDB在系統(tǒng)數(shù)據(jù)庫local中無法創(chuàng)建用戶的解決辦法
這篇文章主要給大家介紹了關(guān)于MongoDB在系統(tǒng)數(shù)據(jù)庫local中無法創(chuàng)建用戶的解決辦法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11mongodb中隨機(jī)獲取1條記錄的實(shí)現(xiàn)方法
這篇文章運(yùn)用實(shí)例給大家演示了如何在mongodb中隨機(jī)獲取1條記錄,文中介紹的很詳細(xì),有需要的朋友們可以參考借鑒。下面來一起看看吧。2016-09-09