MongoDB資料庫設計中6條重要的經驗法則2

2021-07-31 07:50:26 字數 2645 閱讀 1992

一對多中的多是否需要乙個單獨的實體。

這個關係中集合的規模是一對很少,很多,還是非常多。

在掌握了以上基礎技術後,我將會介紹更為高階的主題:雙向關聯和反正規化化。

雙向關聯

如果你想讓你的設計更酷,你可以讓引用的「one」端和「many」端同時儲存對方的引用。

在某些場景中這個應用需要顯示任務的列表(例如顯示乙個多人協作專案中所有的任務),為了能夠快速的獲取某個使用者負責的專案可以在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條的資料也不會導致日誌物件丟失。

通過在查詢中使用投影引數 (類似)的方式在不需要使用logmsgs陣列的情況下避免獲取整個mongodb物件,1000個日誌資訊帶來的網路開銷是很大的。

在一對多的情況下,需要慎重的考慮讀和更新的頻率。冗餘日誌資訊到主機文件物件中只有在日誌物件幾乎不會發生更新的情況下才是個好的決定。

總結 在這篇文章裡,我介紹了對三種基礎方案:內嵌文件,子引用,父引用的補充選擇。

使用雙向引用來優化你的資料庫架構,前提是你能接受無法原子更新的代價。

可以在引用關係中冗餘資料到one端或者n端。

在決定是否採用反正規化化時需要考慮下面的因素:

你將無法對冗餘的資料進行原子更新。

只有讀寫比較高的情況下才應該採取反正規化化的設計。

下次,我將會告訴你在面對這些方案時該如何抉擇。

MongoDB資料庫設計中6條重要的經驗法則(三)

這篇文章是系列的最後一篇。在第一篇文章裡,我介紹了三種針對 一對多 關係建模的基礎方案。在第二篇文章中,我介紹了對基礎方案的擴充套件 雙向關聯和反正規化化。反正規化可以讓你避免一些應用層級別的join,但是這也會讓更新變的更複雜,開銷更大。不過冗餘那些讀取頻率遠遠大於更新頻率的字段還是值得的。讓我們...

資料庫設計20條

使用明確 統一的標明和列名,例如 school,schoolcourse,courceid。資料表名使用單數而不是複數,例如 studentcourse,而不是studentcourses。資料表名不要使用空格。資料表名不要使用不必要的字首或者字尾,例如使用school,而不是tblschool,或...

資料庫設計30條軍規

1 必須使用innodb儲存引擎 1.解讀 支援事務 行級鎖 併發效能更好 cpu及記憶體快取頁優化使得資源利用率更高 2 必須使用utf8字符集 1.解讀 萬國碼,無需轉碼,無亂碼風險,節省空間 3 資料表 資料字段必須加入中文注釋 1.解讀 n年後誰tm知道這個r1,r2,r3欄位是幹嘛的 4 ...