MongoDB資料庫設計中6條重要的經驗法則(二)
在上一篇文章中我介紹了三種基本的設計方案:內嵌,子引用,父引用,同時說明了在選擇方案時需要考慮的兩個關鍵因素。
一對多中的多是否需要一個單獨的實體。
這個關係中集合的規模是一對很少,很多,還是非常多。
在掌握了以上基礎技術後,我將會介紹更為高階的主題:雙向關聯和反正規化化。
雙向關聯
如果你想讓你的設計更酷,你可以讓引用的“one”端和“many”端同時儲存對方的引用。
以上一篇文章討論過的任務跟蹤系統為例。有person和task兩個集合,one-to-n的關係是從person端到task端。在需要獲取person所有的task這個場景下需要在person這個物件中儲存有task的id陣列,如下面程式碼所示。
在某些場景中這個應用需要顯示任務的列表(例如顯示一個多人協作專案中所有的任務),為了能夠快速的獲取某個使用者負責的專案可以在task物件中嵌入附加的person引用關係。
這個方案具有所有的一對多方案的優缺點,但是通過新增附加的引用關係。在task文件物件中新增額外的“owner”引用可以很快的找到某個task的所有者,但是如果想將一個task分配給其他person就需要更新引用中的person和task這兩個物件(熟悉關係資料庫的童鞋會發現這樣就沒法保證操作的原子性。當然,這對任務跟蹤系統來說並沒有什麼問題,但是你必須考慮你的用例是否能夠容忍)
在一對多關係中應用反正規化
在你的設計中加入反正規化,可以使你避免應用層級別的join讀取,當然,代價是這也會讓你在更新是需要操作更多資料。下面我會舉個例子來進行說明
反正規化Many -< One
以產品和零件為例,你可以在parts陣列中冗餘儲存零件的名字。以下是沒有加入反正規化設計的結構。
反正規化化意味著你不需要執行一個應用層級別的join去顯示一個產品所有的零件名字,當然如果你同時還需要其他零件資訊那這個應用層的join是避免不了的。
在使得獲取零件名字簡單的同時,執行一個應用層級別的join會和之前的程式碼有些區別,具體如下:
反正規化化在節省你讀的代價的同時會帶來更新的代價:如果你將零件的名字冗餘到產品的文件物件中,那麼你想更改某個零件的名字你就必須同時更新所有包含這個零件的產品物件。
在一個讀比寫頻率高的多的系統裡,反正規化是有使用的意義的。如果你很經常的需要高效的讀取冗餘的資料,但是幾乎不去變更他d話,那麼付出更新上的代價還是值得的。更新的頻率越高,這種設計方案的帶來的好處越少。
例如:假設零件的名字變化的頻率很低,但是零件的庫存變化很頻繁,那麼你可以冗餘零件的名字到產品物件中,但是別冗餘零件的庫存。
需要注意的是,一旦你冗餘了一個欄位,那麼對於這個欄位的更新將不在是原子的。和上面雙向引用的例子一樣,如果你在零件物件中更新了零件的名字,那麼更新產品物件中儲存的名字欄位前將會存在短時間的不一致。
反正規化One -< Many
你也可以冗餘one端的資料到many端:
如果你冗餘產品的名字到零件表中,那麼一旦更新產品的名字就必須更新所有和這個產品有關的零件,這比起只更新一個產品物件來說代價明顯更大。這種情況下,更應該慎重的考慮讀寫頻率。
在一對很多的關係中應用反正規化
在日誌系統這個一對許多的例子中也可以應用反正規化化的技術。你可以將one端(主機物件)冗餘到日誌物件中,或者反之。
下面的例子將主機中的IP地址冗餘到日誌物件中。
如果想獲取最近某個ip地址的日誌資訊就變的很簡單,只需要一條語句而不是之前的兩條就能完成。
事實上,如果one端只有少量的資訊儲存,你甚至可以全部冗餘儲存到多端上,合併兩個物件。
另一方面,也可以冗餘資料到one端。比如說你想在主機文件中儲存最近的1000條日誌,可以使用mongodb 2.4中新加入的$eache/$slice功能來保證list有序而且只儲存1000條。
日誌物件儲存在logmsg集合中,同時冗餘到hosts物件中。這樣即使hosts物件中超過1000條的資料也不會導致日誌物件丟失。
通過在查詢中使用投影引數 (類似{_id:1})的方式在不需要使用logmsgs陣列的情況下避免獲取整個mongodb物件,1000個日誌資訊帶來的網路開銷是很大的。
在一對多的情況下,需要慎重的考慮讀和更新的頻率。冗餘日誌資訊到主機文件物件中只有在日誌物件幾乎不會發生更新的情況下才是個好的決定。
總結
在這篇文章裡,我介紹了對三種基礎方案:內嵌文件,子引用,父引用的補充選擇。
使用雙向引用來優化你的資料庫架構,前提是你能接受無法原子更新的代價。
可以在引用關係中冗餘資料到one端或者N端。
在決定是否採用反正規化化時需要考慮下面的因素:
你將無法對冗餘的資料進行原子更新。
只有讀寫比較高的情況下才應該採取反正規化化的設計。
下次,我將會告訴你在面對這些方案時該如何抉擇。
原文連結:http://www.jianshu.com/p/21f5a73384d4