標籤:mongodb
MongoDB資料模型和索引學習總結1. MongoDB資料模型:
MongoDB資料存放區結構:
MongoDB針對文檔(大檔案採用GridFS協議)採用BSON(binary json,採用二進位編碼)資料格式來儲存和交換資料。Bson吸收了JSON schema-less的特點,儲存結構鬆散,不需要像RDB(關係資料)那樣事先定義資料存放區的中繼資料結構,另外增加了多種資料類型的支援和最佳化,使讀寫更加高效。
(1) BSON 支援的資料類型:
Double、String、Object、Array、Binary Data、Undefined、Object id、Boolean、Date、Null、Regular Expression、JavaScript、Symbol、JavaScript(with scope)、32-bit integer、Timestamp、64-bitInteger、Min key、Max key
(2) BSON 在表現形式如下:
{ "_id" : ObjectId("542c2b97bac0595474108b48"), "ts" : Timestamp(1412180887, 1),"name":"steven"}
(3) BSON 是MongoDB中的通訊協定和資料存放區格式: 在MongoDB中用戶端和服務端通訊採用的是BSON的文檔格式,例如查詢一段資料,需要這樣寫:
db.steven.find({"name":"steven"})
更新一段資料需要這樣寫:
db.steven.update({"name":"steven"},{$set:{"name":"jianying"}})
刪除一段資料需要這樣寫:
db.steven.remove({"name":"steven"})
總之MongoDB中針對文檔的CRUD的RPC通訊格式均支援採用了BSON的資料格式。並且其儲存格式也採用了BSON的格式類似:
{ "_id" : ObjectId("542c2b97bac0595474108b48"), "ts" : Timestamp(1412180887, 1),"name":"steven"}
(4) BSON資料格式的編碼:
BSON的String類型均採用UTF-8編碼,其中KV結構中 K值 和 字串類型的V值,均採用UTF-8格式編碼。如果使用的是其他格式則需要轉碼。並且針對K 值可以採用除以下要求外的任意UTF-8字元:
a.鍵不能含有\o(Null 字元)b.$和.有特殊的含義,只有在特定環境下採用使用c.以底線"_"開頭的鍵是保留的(不是嚴格要求的)
而其它值類型的編碼則按照具體資料類型的內建協議編碼。MongoDB在資料模型的組織方式上,支援文檔的引用和嵌套。具體介紹如下。
資料模型設計模式 - 引用 和 嵌套:
以引用的方式儲存資料是一種MongoDB組織資料存放區結構的模式,即一個文檔中儲存了檢索另一個文檔需要的必要資訊,舉例如下:
{ _id: "joe", name: "Joe Bookreader"}{ patron_id: "joe", street: "123 Fake Street", city: "Faketon", state: "MA", zip: "12345"}
上面的文檔是使用者joe的資訊,而下面那個文檔則記錄了他的地址資訊,要根據joe的name檢索地址資訊,則需要先檢索第一個文檔,然後再檢索第二個文檔。而設計成 嵌套模式則表現為:
{ _id: "joe", name: "Joe Bookreader", addresses: [ { street: "123 Fake Street", city: "Faketon", state: "MA", zip: "12345" } ] }
這兩種設計模式的均有各自的優缺點,參考模式被認為是正常化的模式,減小了資料存放區的冗餘,結構設計清爽簡單。符合我們一般設計原則,但是要擷取完整資料的通訊開銷比較大,而且多個文檔操作的原子性在MongoDB層面無法保證。 而被認為非正常化的嵌套設計模式,則具備相反的特性,其有點是減少了通訊的成本,並且原子性在單條文檔得以保證,缺點就是資料存在冗餘。選擇哪種資料群組織方式其實是一種權衡(trade-off)。
注意點:
(1) MongoDB 文檔的大小必須小於16M,超過這個大小的話,要考慮使用GirdFs。
(2) 加入的文檔大小超出原先分配給它的空間,MongoDB會把這個文檔移動到磁碟的另外一個位置。遷移文檔比原位更新更要耗時,也會因此導致磁碟片段問題。
(3) 在MongoDB裡面,操作的原子性層級保證到 document層級。
(4) Bson 字串採用UTF-8編碼。
2. MongoDB索引結構:
MongoDB支援索引的類型:
MongoDB採用B樹的結構來組織索引(有效支援等值查詢和範圍查詢),支援針對文檔中任意欄位構建索引,不論是單值、數組、文本、嵌套結構的欄位,均可構建索引。MongoDB 針對BSON儲存格式是一種全索引的支援策略。面對多而強大的Mongo索引,索引的設計對效能的提升有比較大的影響。目前最新MongoV3.0版本支援的索引類型有如下幾種:
索引類型 簡述 Default _id 預設ID索引:Mongo預設構建唯一性索引的id欄位,每個文檔都有一個_id欄位。Single Field 單值索引:針對文檔的某一欄位或或嵌套文檔的某一欄位構建索引。Compound Index 複合式索引:將多個欄位放在一起構建索引,欄位索引間組成上下層的樹形結構。Multikey Index 多值索引:針對數群組類型的索引結構,為數組的每個值建立一個索引。Geospatial Index 地理位置索引: 針對地理座標結構,構建索引,能高效定位座標範圍,屬額外福利。Text indexes 文本索引:類似搜尋引擎的文本檢索,涉及到分詞操作,可惜不支援中文,而且查詢文法的支援相對單一。Hashed Indexes 雜湊索引:為了支援 基於Hash的Sharding(一種部署方式)而生,只支援等值檢索,不支援範圍檢索。
以上介紹了索引的類型,而不同類型的索引又可以帶有以下屬性,間接如下:
- 索引的屬性:
(1) 唯一索引: 和RDB(關係型資料庫)的唯一性索引的概念一致,為了避免出現重複的值而設計。
構建方式如:
db.members.createIndex( { "user_id": 1 }, { unique: true } )
(2) 稀疏索引: 稀疏索引的稀疏性體現在,其只為那些包含索引欄位的文檔構建索引Entry。忽略那些不包含索引欄位的文檔。
構建方式如:
db.addresses.createIndex( { "xmpp_id": 1 }, { sparse: true } )
(3) TTL索引: TTL顧名思義是生命週期的意思,即儲存的document儲存帶有到期時間屬性,超過生命週期自動刪除,像日誌資料、系統自動產生的臨時資料、會話資料等均符合這一情境。
構建方式如:
db.log_events.createIndex( { "createdAt": 1 }, { expireAfterSeconds: 3600 } )
(1) B樹結構,順序儲存:MongoDB的索引均採用B樹的結構組織,支援高效的等值查詢和範圍查詢。且內部索引項目(entry)是預設有序的,可以天然保證返回結果有序。
(2) 索引的排序:構建索引是可以指定索引項目是按照升序或降序構建,升序或降序的選擇對於單值索引來說是等效的,但是對於複合式索引則不等學效,複合式索引被組織成上下級的樹形結構,升序或降序選擇錯誤,會對效能產生較大影響。
(3) 索引的交集:2.6版本以後,索引的查詢最佳化策略支援索引的交集,可以將多條索引組合來使用,最高效的檢索資料。例如可以構建兩條單獨的索引,當查詢條件關聯到這兩條索引的時候,索引最佳化計劃會自動組合這兩條索引來檢索。
例如構建了如下2條索引:
{ qty: 1 }{ item: 1 }
則以下查詢語句會命中以上兩條索引:
db.orders.find( { item: "abc123", qty: { $gt: 15 } } )
另外索引的交集和包括:
索引的首碼交集:主要針對複合式索引,查詢計劃會最佳化複合式索引的首碼來查詢。
(1) 評估RAM容量,盡量保證索引在記憶體中:
查詢索引大小的命令(單位是位元組):
db.collection.totalIndexSize() db.collection.stats()
(2) 分析查看索引的計劃:
MongoDB中使用explain和hint可以查看索引的策略:
db.collection.find().explain()
可以看出那條索引策略生效,以及索引交集的使用方式。
db.collection.find().hint({"name":1})
hint的命令則可以指定強制使用某條索引。
(3) 索引的管理資訊: 每個DB下面都會有一個system.indexes集合,這個集合記錄著DB下,索引構建的中繼資料資訊。
db.system.indexes.find()
- 注意點:
(1) 每個索引需要至少8K的空間。
(2) MongoDB 會對 _id欄位自動建立唯一索引。
(3) 一個特別的索引類型支撐了TTL集合的實現,TTL依賴一個在Mongod中的後台線程,該線程讀取索引中日期類型的值並從集合中刪除到期的documents。
MongoDB資料模型和索引學習總結