1. 程式人生 > >MongoDB Schema Design(MongoDB模式設計)

MongoDB Schema Design(MongoDB模式設計)

Document-Orientation

     在描述中,MongoDB是面向文件的,意味著在這種資料庫中主要儲存單位是Collection。

     一些常見的資料格式例如:JSON、XML、簡單的鍵/值對。

     儲存在MongoDB中的文件是一種類JSON格式,為了得到更高的效率,使用了一種二進位制表現形式且被稱為BSON的格式。目標是使資料更緊湊和合理以便於掃描。

     客戶端序列化資料成BSON傳送至資料庫中,資料是以BSON格式被儲存的。因此,讀取資料的時候,資料庫只需做很小的解析處理就可以傳送出去,更加高效。然後客戶端在反序列化BSON格式為當前語言使用的格式。

   JSON

    一段資料:

Mongo程式碼 
  1. { author: 'joe',  
  2.   created : new Date('03-28-2009'),  
  3.   title : 'Yet another blog post',  
  4.   text : 'Here is the text...',  
  5.   tags : [ 'example''joe' ],  
  6.   comments : [ { author: 'jim', comment: 'I disagree' },  
  7.               { author: 'nancy', comment: 'Good post'
     }  
  8.   ]  
  9. }  

     儲存的例項:

Mongo程式碼 
  1. > doc = { author : 'joe', created : new Date('03-28-2009'), ... }  
  2. > db.posts.insert(doc);  

   Mongo-Friendly Schema

     Mongo可以用於很多方面,第一反應或許是如何用它來編寫一個使用關係資料庫的應用程式。雖然這項工作非常好,但是也不能展現Mongo的真正力量。Mongo就是被設計和工作在副

   Store Example

Mongo程式碼 
  1. item  
  2.    title  
  3.    price  
  4.    sku  
  5. item_features  
  6.    sku  
  7.    feature_name  
  8.    feature_value  

    不同的商品有不同的屬性,但又不想在一張表中包含所有可能出現的屬性。(一般關係資料庫中,可能都會另建屬性表,跟分類表類似)在Mongo中同樣可以建立這個模型,而且更加高效。

Mongo程式碼 
  1. item : {  
  2.          "title" : <title> ,  
  3.          "price" : <price> ,  
  4.          "sku"   : <sku>   ,  
  5.          "features" : {  
  6.             "optical zoom" : <value> ,  
  7.             ...  
  8.          }  
  9. }  

    這樣做有幾個好處:

    1、一次資料庫查詢可以得到整條記錄。。

    2、一條記錄的所有資訊都書儲存在硬碟的的同一片區域,所以一次檢索可以可以得到所有資料。

    3、插入或更新單條屬性時:

Mongo程式碼 
  1. 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程式碼 
  1. print( student.address.city );  

     address是嵌入式物件,所以這個操作通常是很快速的,如果sdudent被放在記憶體中,那address也通常在記憶體中。然而下面這個例子:

Mongo程式碼 
  1. print( student.scores[0].for_course.name );  

     如果是第一次訪問scores[0]的內容,會先執行下面這句:

Mongo程式碼 
  1. // pseudocode for driver or framework, not user code  
  2. 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.
  • 排序欄位一定建立索引.