MongoDB Schema Design(MongoDB模式設計)
Document-Orientation
在描述中,MongoDB是面向文件的,意味著在這種資料庫中主要儲存單位是Collection。
一些常見的資料格式例如:JSON、XML、簡單的鍵/值對。
儲存在MongoDB中的文件是一種類JSON格式,為了得到更高的效率,使用了一種二進位制表現形式且被稱為BSON的格式。目標是使資料更緊湊和合理以便於掃描。
客戶端序列化資料成BSON傳送至資料庫中,資料是以BSON格式被儲存的。因此,讀取資料的時候,資料庫只需做很小的解析處理就可以傳送出去,更加高效。然後客戶端在反序列化BSON格式為當前語言使用的格式。
JSON
一段資料:
Mongo程式碼- { author: 'joe',
- created : new Date('03-28-2009'),
- title : 'Yet another blog post',
- text : 'Here is the text...',
- tags : [ 'example', 'joe' ],
- comments : [ { author: 'jim', comment: 'I disagree' },
-
{ author: 'nancy', comment: 'Good post'
- ]
- }
儲存的例項:
Mongo程式碼- > doc = { author : 'joe', created : new Date('03-28-2009'), ... }
- > db.posts.insert(doc);
Mongo-Friendly Schema
Mongo可以用於很多方面,第一反應或許是如何用它來編寫一個使用關係資料庫的應用程式。雖然這項工作非常好,但是也不能展現Mongo的真正力量。Mongo就是被設計和工作在副
Store Example
Mongo程式碼-
item
- title
- price
- sku
- item_features
- sku
- feature_name
- feature_value
不同的商品有不同的屬性,但又不想在一張表中包含所有可能出現的屬性。(一般關係資料庫中,可能都會另建屬性表,跟分類表類似)在Mongo中同樣可以建立這個模型,而且更加高效。
Mongo程式碼- item : {
- "title" : <title> ,
- "price" : <price> ,
- "sku" : <sku> ,
- "features" : {
- "optical zoom" : <value> ,
- ...
- }
- }
這樣做有幾個好處:
1、一次資料庫查詢可以得到整條記錄。。
2、一條記錄的所有資訊都書儲存在硬碟的的同一片區域,所以一次檢索可以可以得到所有資料。
3、插入或更新單條屬性時:
Mongo程式碼- db.items.update( { sku : 123 } , { "$set" : { "features.zoom" : "5" } } )
4、插入一條新屬性不需要在硬碟上移動整條記錄,Mongo有一個預留機制,預留出了一部分空間以適應資料物件的增長。也可以預防索引的增長等問題。
Legal Key Names
鍵的命名有以下限制:
1. $不能出作為第一個字元
2.(.)點不能出現在鍵名中
Schema Design(資料庫設計)
Introduction
在Mongo裡,比起設計資料庫關係模式,你只需做很少的標準化工作, because there are no server-side "joins"。通常來說,都希望每個頂級物件對應一個Collection。
每一種分類都建立一個Collection,只需建立一個嵌入式物件。例如在下面的圖中,我們有兩個Collection,student和coureses。學生Collection中包含一個嵌入的address文件和coursesCollection有聯絡的score文件。
如果用關係資料庫來設計,幾乎肯定會把score分離出來單獨做一張表,然後加一個外來鍵和student相連。
Embed vs. Reference
在Mongo資料庫設計中關鍵的一句話是“比起嵌入到其他Collection中做一個子物件,每個物件值得擁有自己的Collection嗎?”。在關係資料庫中。每個有興趣的子專案通常都會分離出來單獨設計一張表(除非為了效能的考慮)。而在Mongo中,是不建議使用這種設計的,嵌入式的物件更高效。(這句不是很確定Data is then colocated on disk; client-server turnarounds to the database are eliminated)資料是即時同步到硬碟上的,客戶端與伺服器不必要在資料庫上做週轉。所以通常來說問題就是“為什麼不使用嵌入式物件呢?”
利用上面的例子,我們來看下為什麼引用比較慢
Mongo程式碼- print( student.address.city );
address是嵌入式物件,所以這個操作通常是很快速的,如果sdudent被放在記憶體中,那address也通常在記憶體中。然而下面這個例子:
Mongo程式碼- print( student.scores[0].for_course.name );
如果是第一次訪問scores[0]的內容,會先執行下面這句:
Mongo程式碼- // pseudocode for driver or framework, not user code
- student.scores[0].for_course = db.courses.findOne({_id:_course_id_to_find_});
因此,每一次引用遍歷都是一個數據庫查詢。一般來說,有問題的Collection都是預設的在_id建有索引,查詢會稍微快一些。然而即使所有的資料都快取在記憶體中,鑑於伺服器端/客戶端 的應用程式和資料庫通訊時仍然會有一些延遲。一般來說,期望在查詢時快取命中的境況下有1ms。因此,如果我們迭代1000 student,查詢即使在有快取的情況下仍然是很慢的,超過1m。如果我們只需要查詢一條記錄,時間應該在1ms左右,這對於一個網頁載入來說是可以接受的。(注意:如果資料已經在快取中,取出1000條資料也許花費時間少於1m,)
一些規則:
1、頂級物件,一般都有自己的Collection
2、線性細節物件,一般作為嵌入式的
3、一個物件和另一個物件是包含關係時通常採用嵌入式設計
4、多對多的關係通常採取引用設計
5、只含有幾個簡單物件的可以單獨作為一個Collection,因為整個Collection可以很快的被快取在應用程式伺服器記憶體中。
6、在Collection中嵌入式物件比頂級物件更難引用。as you cannot have a DBRef to an embedded object (at least not yet).
7、It is more difficult to get a system-level view for embedded objects. For example, it would be easier to query the top 100 scores across all students if Scores were not embedded.
8、如果將要嵌入的資料量很大(很多M),你可以限制單個物件的大小
9、如果效能存在問題,請使用嵌入式設計
原文 寫道 * "First class" objects, that are at top level, typically have their own collection.* Line item detail objects typically are embedded.
* Objects which follow an object modelling "contains" relationship should generally be embedded.
* Many to many relationships are generally by reference.
* Collections with only a few objects may safely exist as separate collections, as the whole collection is quickly cached in application server memory.
* Embedded objects are harder to reference than "top level" objects in collections, as you cannot have a DBRef to an embedded object (at least not yet).
* It is more difficult to get a system-level view for embedded objects. For example, it would be easier to query the top 100 scores across all students if Scores were not embedded.
* If the amount of data to embed is huge (many megabytes), you may reach the limit on size of a single object.
* If performance is an issue, embed.
Use Cases
來看幾個例項
1、客戶/訂單/訂單專案
訂單必須作為一個Collection,客戶作為一個Collection,訂單專案必須作為一個子陣列嵌入到訂單Collection中
2、部落格系統
posts應該作為一個Collection,auth可以作為一個單獨的Collection,或者auth包含的欄位很少,比如只有email,address之類的為了更高的效能,也應該設計為嵌入式的物件.
Index Selection
資料庫設計的第二個方面是索引的選擇,一般規則:在mysql中需要的索引,在Mongo中也同樣需要.
- _id欄位是自動被索引的
- Fields upon which keys are looked up should be indexed.
- 排序欄位一定建立索引.