資料庫設計冗餘欄位問題?

日常工作中 經常看到有人設計表結構的時候 喜歡冗餘欄位 比如 訂單表 裡面 有用戶ID 然後再把用戶名稱冗餘進去。大部分場景下用戶都會被緩存,取訂單時根據ID 再去緩存拉一下用戶 是否更合理,另外類似於這種被join的表欄位(用戶名稱)冗餘後 不會做為查詢條件情況是否都沒有任何意義?


要分清楚場景,有些是屬於快照,有些是屬於冗餘。

1.快照場景:交易場景大部分是數據快照,而不是冗餘,用戶下單時候的用戶名、地址、商品名稱、商品描述等,若採用關聯,商品在下單後發生了更新的話再去關聯查詢就會導致和用戶操作時的數據不一致,從而產生糾紛。

2.冗餘場景:一般數據改動的可能性少,而查詢多的場景會使用冗餘,例如淘寶的店鋪名稱,淘寶商家中心會有這個欄位,可能裡面的商家論壇也有,再假設聚划算這種獨立的大業務自己也存一份,再來個垂直頻道電器城的後台管理也獨立存一份,這種場景是由於對查詢性能要求高產生的,所以必須要冗餘,在業務的取捨上,肯定是對讓用戶更快看到信息,那麼不可避免的是帶來維護成本的增加,對於數據一致性問題,只要做到最終一致就可以了,分散式的CAP原則的實際應用基本都是通過犧牲數據一致性(C)來保證高可用(A)和高可靠(P), 因為這種場景大部分都是可以接受短暫的數據不一致的,對業務的影響及其微小。

ps:例子可能舉得不是很恰當,自己意會- -!


謝邀。

一句話這類冗餘都是為了解決資料庫的性能限制(尤其是對於伺服器性能需要精打細算的情況下)。

如果參照三範式,那我們在設計資料庫的時候就必須致力於消滅冗餘欄位,畢竟如果我們需要更新某條記錄,而這條記錄又恰好包含了冗餘欄位,那麼我就必須更新所有攜有冗餘欄位的表。如果冗餘冗餘欄位只出現在很少的表中那麼這不算什麼大問題。但是如果有很多很多張表都攜有冗餘欄位,不僅會使資料庫性能降低還會帶來數據不一致等一系列問題。所以,我們目前所接觸的經典教材都在強調三範式還是很有道理的。

如果用戶表添加計數欄位,好處在於用空間換時間,查詢速度肯定快多了;如果追求簡潔無冗餘,好處在於清晰易懂,寫代碼不蔓不枝,特別漂亮。

如果用戶表添加計數欄位,壞處在於難以維護。當你添加一個粉絲關係的時候需要更新關注數和粉絲數,當你刪除一個粉絲關係的時候也需要更新關注數和粉絲數。當你刪除一個用戶的時候,與他相關的所有粉絲關係、關注關係都要刪除,相對應的粉絲數關注數也要刪除,這個動作怎麼完成呢?通過java代碼,那就要把全部信息讀到內存中去,邏輯挺複雜,先刪除誰,後刪除誰,如果有好幾層(用戶-話題-帖子-評論)那就不好整了。如果通過觸發器+級聯刪除的方式,觸發器好理解,在插入刪除時update一下就可以了。如果用到級聯刪除,那就必然用到外鍵,在創建外鍵的時候添加一句on delete cascade,一旦級聯刪除,那麼觸發器語句就失靈了,比如,你刪除了話題,話題下的帖子被級聯刪除了,用戶的帖子數卻不會發生變化,因為級聯刪除的東西不會觸動觸發器!於是我說,那我就單單用觸發器,不再使用外鍵+級聯刪除了,因為觸發器完全可以實現級聯刪除的功能,只不過寫的刪除時觸發語句比較長罷了。可是,也不行。因為觸發器和函數禁止循環調用,比如我刪除了話題,觸發刪除相關帖子,刪除相關帖子時,就會觸發更新話題的帖子數,這就形成了一個循環,運行時報錯!運行時報錯!寫在觸發器語句中的東西編譯不報錯運行時報錯。

如果不設計冗餘欄位,也慢不了多少,建立完外鍵或者索引之後查詢速度會提升很多。如果覺得這麼整寫sql語句會變長不如冗餘欄位好看,那也簡單,建立視圖呀,看上去跟冗餘欄位差不多,但它的內心卻是十分純潔不像冗餘欄位繁瑣難維護。

如果冗餘欄位可控容易維護,那麼維護它;如果冗餘欄位不可控,那麼冗餘的毫無價值,刪除掉追求簡潔。


如果要儘可能避免多表連接查詢,那在設計資料庫時,有關聯關係的地方,一般從表中除了有引用主表主鍵的外鍵欄位外,還要有一個或多個欄位存放主表中的關鍵信息,比如病人表中有所屬醫院所屬科室主鍵的外鍵欄位,但還可能會有所屬醫院名稱所屬科室名稱的欄位。因為嫌數據冗餘、維護不易,之前自己一般不設計除外鍵外存放主表信息的其它欄位,但這樣查詢時又會多添好些麻煩。可如果加上這些欄位,不單單數據冗餘、維護麻煩,也不好保證數據的準確協調統一性。比如如果醫院的名稱被修改了,那按常理病人表中的醫院名稱也得做相應的修改才可以,這樣,如果醫院表被許多表引用,那就得對所有的表執行修改動作,很是麻煩,實現起來也不現實。如果都加上引用約束,依賴資料庫自己的關聯自動更新,覺得也不是很好,影響程序執行速度且不易維護。可如果是在會診單表(類似於訂單表的功能)中出現類似的情況,就無須有這種顧慮,如果這個會診單在產生時醫院是這個名稱,後面名稱有了更改,那會診單中的醫院名稱還是顯示早前的即可,無須做相應更改,這也是符合邏輯的。

類似情況經常出現在字典相關信息的存取中,平時只在表中存字典編碼,但查詢時又往往要求同時提供字典文本,核心業務表中的字典欄位往往比較多,暫時沒有好的方法一次高效提取完整信息。後面在做類似設計時,核心業務表,字典欄位比較多的,根據實際情況,考慮同時存入字典編碼和字典文本,這樣可避免部分連接查詢。但同時,還是會出現上面提到的問題,一方面是數據冗餘,一方面業務表中的字典文本有可能會和字典表中的文本不一致——如果字典信息有更改的話。

這裡很難找到一種兩全其美的辦法,既能避免數據冗餘,又能讓程序在執行讀和寫動作時都方便高效,如何在各方面之間拿捏均衡是個人經驗問題。通常情況下,是在數據的協調性、準確性允許,跨表查詢又不容易(從表外鍵較多)的業務模塊,採用在從表中附加額外欄位的處理方式;在對數據顯示的同步性、準確性有嚴格要求,跨表查詢也相對容易(從表外鍵較少)的業務模塊,採用從表中不設外鍵以外的附加欄位、而使用關聯查詢的方式獲取完整數據信息。

在普通的業務系統之外,還有一種情況,可能不得不大量使用函數、子查詢、嵌套查詢。和可視化部門合作過的一些項目,系統前端引入ECharts,大量的環形圖、柱狀圖、折線圖等用於展現數據統計分析結果。有些圖形需要的數據很難用簡單的SQL一次提取出來,可如果多次提取後再由程序組裝處理,又太過麻煩,最後還得考驗SQL,此種情況是允許子查詢、嵌套查詢、多表連接等複雜SQL出現的。

過去曾藉助外部框架設計出一套異常靈活的架構,封裝了查詢對象,消除掉了SQL語句,應付通用的業務系統足夠,但在做類似這種統計分析功能時卻變得各種不自在,到後來還是覺得直接寫SQL更方便。此處只能在設計的架構上放開一個口,讓開發人員可以自由編寫SQL語句提取數據,最終的查詢結果統一封裝成一個List&&>,然後交由程序自動序列化成JSON格式(包含多個對象的數組)返回給前端。


你問題中的例子,不是冗餘欄位,是必須要這樣設計.

訂單,交易流水,操作日誌這種和日期時間相關的表一定要儘可能的把和訂單關係比較緊密的信息信息複製到訂單表裡. 例如訂單表會複製,用戶名,地址,電話,郵編,商品名稱 等


冗餘欄位,是設計數據的時候常用的一種手段。優點是,可以在很大程度上避免資料庫的關聯查詢,不使用join提升查詢速度。缺點是,數據一致性維護成本高,需要維護冗餘欄位的一致性。


根據實際情況來看的,比如我需要用戶id關聯兩張表,也需要提供用戶姓名的,這時候不需要再關聯員工表進行三表關聯去取用戶的姓名,這時候對語句的執行效率是提高的


推薦閱讀:

國家能不能建立一個新生兒DNA比對資料庫來預防小孩被拐賣?
互聯網產品採用哪些方案可以實現多賬號綁定、合併和解綁?
資料庫有沒有類似現代操作系統的好書?
一個高級資料庫管理員或者老練的DBA都具備哪些逆天的技巧?
像知乎這樣的評論回復模式,資料庫應該怎麼設計比較好,考慮性能、可擴展性等?

TAG:資料庫 | SQL | MySQL | 資料庫設計 | 資料庫管理系統 |