在這章中,我們來講幾個(gè)關(guān)于性能的話題,以及在 MongoDB 開發(fā)中用到的一些工具。我們不會深入其中的一個(gè)話題,不過我們會指出每個(gè)話題中最重要的方面。
首先我們要介紹一個(gè)特殊的集合?system.indexes
?,它保存了我們數(shù)據(jù)庫中所有的索引信息。索引的作用在 MongoDB 中和關(guān)系型數(shù)據(jù)庫基本一致: 幫助改善查詢和排序的性能。創(chuàng)建索引用?ensureIndex
?:
// where "name" is the field name
db.unicorns.ensureIndex({name: 1});
刪除索引用?dropIndex
:
db.unicorns.dropIndex({name: 1});
可以創(chuàng)建唯一索引,這需要把第二個(gè)參數(shù)?unique
?設(shè)置為?true
:
db.unicorns.ensureIndex({name: 1},
{unique: true});
索引可以內(nèi)嵌到字段中 (再說一次,用點(diǎn)號) 和任何數(shù)組字段。我們可以這樣創(chuàng)建復(fù)合索引:
db.unicorns.ensureIndex({name: 1,
vampires: -1});
索引的順序 (1 升序, -1 降序) 對單鍵索引不起任何影響,但它會在使用復(fù)合索引的時(shí)候有所不同,比如你用不止一個(gè)索引來進(jìn)行排序的時(shí)候。
閱讀?indexes page?獲取更多關(guān)于索引的信息。
需要檢查你的查詢是否用到了索引,你可以通過?explain
?方法:
db.unicorns.find().explain()
輸出告訴我們,我們用的是?BasicCursor
?(意思是沒索引), 12 個(gè)對象被掃描,用了多少時(shí)間,什么索引,如果有索引,還會有其他有用信息。
如果我們改變查詢索引語句,查詢一個(gè)有索引的字段,我們可以看到?BtreeCursor
?作為索引被用到填充請求中去:
db.unicorns.find({name: 'Pilot'}).explain()
MongoDB 的復(fù)制在某些方面和關(guān)系型數(shù)據(jù)庫的復(fù)制類似。所有的生產(chǎn)部署應(yīng)該都是副本集,理想情況下,三個(gè)或者多個(gè)服務(wù)器都保持相同的數(shù)據(jù)。寫操作被發(fā)送到單個(gè)服務(wù)器,也即主服務(wù)器,然后從它異步復(fù)制到所有的從服務(wù)器上。你可以控制是否允許從服務(wù)器上進(jìn)行讀操作,這可以讓一些特定的查詢從主服務(wù)器中分離出來,當(dāng)然,存在讀取到舊數(shù)據(jù)的風(fēng)險(xiǎn)。如果主服務(wù)器異常關(guān)閉,從服務(wù)中的一個(gè)將會自動晉升為新的主服務(wù)器繼續(xù)工作。另外,MongoDB 的復(fù)制不在本書的討論范圍之內(nèi)。
MongoDB 支持自動分片。分片是實(shí)現(xiàn)數(shù)據(jù)擴(kuò)展的一種方法,依靠在跨服務(wù)器或者集群上進(jìn)行數(shù)據(jù)分區(qū)來實(shí)現(xiàn)。一個(gè)最簡單的實(shí)現(xiàn)是把所有的用戶數(shù)據(jù),按照名字首字母 A-M 放在服務(wù)器 1 ,然后剩下的放在服務(wù)器 2。謝天謝地,MongoDB 的拆分能力遠(yuǎn)比這種分法要強(qiáng)。分片不在本書的討論范圍之內(nèi),不過你應(yīng)當(dāng)有分片的概念,并且,當(dāng)你的需求增長超過了使用單一副本集的時(shí)候,你應(yīng)該考慮它。
盡管復(fù)制有時(shí)候可以提高性能(通過將長時(shí)間查詢隔離到從服務(wù)器,或者降低某些類型的查詢的延遲),它的主要目的是維護(hù)高可用性。分片是擴(kuò)展 MongoDB 集群的主要方法。把復(fù)制和分片結(jié)合起來實(shí)現(xiàn)可擴(kuò)展和高可用性是禁術(shù)。
你可以通過?db.stats()
?查詢數(shù)據(jù)庫的狀態(tài)?;旧隙际顷P(guān)于數(shù)據(jù)庫大小的信息。你還可以查詢集合的狀態(tài),比如說unicorns
?集合,可以輸入?db.unicorns.stats()
。基本上都是關(guān)于集合大小的信息,以及集合的索引信息。
你可以這樣執(zhí)行 MongoDB profiler :
db.setProfilingLevel(2);
啟動之后,我們可以執(zhí)行一個(gè)命令:
db.unicorns.find({weight: {$gt: 600}});
然后檢查 profiler:
db.system.profile.find()
輸出會告訴我們:什么時(shí)候執(zhí)行了什么,有多少文檔被掃描,有多少數(shù)據(jù)被返回。
你要停止 profiler 只需要再調(diào)用一次?setProfilingLevel
?,不過這次參數(shù)是?0
。指定?1
?作為第一個(gè)參數(shù),將會過濾統(tǒng)計(jì)超過 100 milliseconds 的任務(wù). 100 milliseconds 是默認(rèn)的閾值,你可以在第二個(gè)參數(shù)中,指定不同的閾值時(shí)間,以 milliseconds 為單位:
//profile anything that takes
//more than 1 second
db.setProfilingLevel(1, 1000);
在 MongoDB 的?bin
?目錄下有一個(gè)可執(zhí)行文件?mongodump
?。簡單執(zhí)行?mongodump
?會鏈接到 localhost 并備份你所有的數(shù)據(jù)庫到?dump
?子目錄。你可以用?mongodump --help
?查看更多執(zhí)行參數(shù)。常用的參數(shù)有?--db DBNAME
?備份指定數(shù)據(jù)庫和--collection COLLECTIONNAME
?備份指定集合。你可以用?mongorestore
?可執(zhí)行文件,同樣在?bin
?目錄下,還原之前的備份。同樣,?--db
?和?--collection
?可以指定還原的數(shù)據(jù)庫和/或集合。?mongodump
?和?mongorestore
?使用 BSON,這是 MongoDB 的原生格式。
比如,來備份我們的?learn
?數(shù)據(jù)庫導(dǎo)?backup
?文件夾,我們需要執(zhí)行(在控制臺或者終端中執(zhí)行該命令,而不是在 mongo shell 中):
mongodump --db learn --out backup
如果只還原?unicorns
?集合,我們可以這樣做:
mongorestore --db learn --collection unicorns \
backup/learn/unicorns.bson
值得一提的是,?mongoexport
?和?mongoimport
?是另外兩個(gè)可執(zhí)行文件,用于導(dǎo)出和從 JSON/CSV 格式文件導(dǎo)入數(shù)據(jù)。比如說,我們可以像這樣導(dǎo)出一個(gè) JSON:
mongoexport --db learn --collection unicorns
CSV 格式是這樣:
mongoexport --db learn \
--collection unicorns \
--csv --fields name,weight,vampires
注意?mongoexport
?和?mongoimport
?不一定能正確代表數(shù)據(jù)。真實(shí)的備份中,只能使用?mongodump
?和?mongorestore
?。 你可以從 MongoDB 手冊中讀到更多的?備份須知?。
在這章中我們介紹了 MongoDB 的各種命令,工具和性能細(xì)節(jié)。我們沒有涉及所有的東西,不過我們已經(jīng)把常用的都看了一遍。MongoDB 的索引和關(guān)系型數(shù)據(jù)庫中的索引非常類似,其他一些工具也一樣。不過,在 MongoDB 中,這些更易于使用。
更多建議: