還記得數據庫設計的六大範式嗎?一篇文章讓你完全搞懂

數據庫範式是為解決關係數據庫中數據冗餘、更新異常、插入異常、刪除異常問題而引入的。簡單的理解,數據庫範式可以避免數據冗餘,減少數據庫的空間,並且減輕維護數據完整性的麻煩。

還記得數據庫設計的六大範式嗎?一篇文章讓你完全搞懂

第一範式(1NF)

第一範式,強調屬性的原子性約束,要求屬性具有原子性,不可再分解。

舉個例子,活動表(活動編碼,活動名稱,活動地址),假設這個場景中,活動地址可以細分為國家、省份、城市、市區、位置,那麼就沒有達到第一範式。

第二範式(2NF)

第二範式,強調記錄的唯一性約束,表必須有一個主鍵,並且沒有包含在主鍵中的列必須完全依賴於主鍵,而不能只依賴於主鍵的一部分。

舉個例子,版本表(版本編碼,版本名稱,產品編碼,產品名稱),其中主鍵是(版本編碼,產品編碼),這個場景中,數據庫設計並不符合第二範式,因為產品名稱只依賴於產品編碼。存在部分依賴。所以,為了使其滿足第二範式,可以改造成兩個表:版本表(版本編碼,產品編碼)和產品表(產品編碼,產品名稱)。

第三範式(3NF)

第三範式,強調屬性冗餘性的約束,即非主鍵列必須直接依賴於主鍵。

舉個例子,訂單表(訂單編碼,顧客編碼,顧客名稱),其中主鍵是(訂單編碼),這個場景中,顧客編碼、顧客名稱都完全依賴於主鍵,因此符合第二範式,但是顧客名稱依賴於顧客編碼,從而間接依賴於主鍵,所以不能滿足第三範式。為了使其滿足第三範式,可以拆分兩個表:訂單表(訂單編碼,顧客編碼)和顧客表(顧客編碼,顧客名稱),拆分後的數據庫設計,就可以完全滿足第三範式的要求了。

值得注意的是,第二範式的側重點是非主鍵列是否完全依賴於主鍵,還是依賴於主鍵的一部分。第三範式的側重點是非主鍵列是直接依賴於主鍵,還是直接依賴於非主鍵列。

修正的第三範式(BCNF)

修正的第三範式,是防止主鍵的某一列會依賴於主鍵的其他列。

舉個例子,每個管理員只能管理一個倉庫,那麼如果設計庫存表(倉庫名,管理員名,商品名,數量),主鍵為(倉庫名,管理員名,商品名),這是滿足前面三個範式的,但是倉庫名和管理員名之間存在依賴關係,因此刪除某一個倉庫,會導致管理員也被刪除,因此設計不合理。

第四範式(4NF)

當一個表中的非主屬性相互獨立時(3NF),這些非主屬性不應該有多值。如果有多值就違反了第四範式。舉個例子,有一個用戶聯繫方式表(用戶id,固定電話,移動電話),其中用戶id是主鍵,這個滿足了BCNF,但是一個用戶有可能會有多個固定電話或者多個移動電話,那麼這種設計就不合理,應該改為(用戶id,聯繫方式類型,電話號碼)。在實際應用中,一般不要求表滿足第四範式。

還記得數據庫設計的六大範式嗎?一篇文章讓你完全搞懂

第五範式(5NF)

第五範式是最終範式,消除了4NF中的連接依賴,第五範式有以下要求:

1. 必須滿足第四範式

2.表必須可以分解為較小的表,除非那些表在邏輯上擁有與原始表相同的主鍵。

和第四範式不同的是,第四範式處理的是項目獨立的多值情況,幾多個屬性的多值是相互獨立的,沒有關聯關係,如固定電話和移動電話之間不會有任務關係。而第五範式是處理存在關聯關係的冗餘情況。例如下表:銷售信息表(銷售人員,供貨商,產品),設計這麼一張表,主鍵為(銷售人員,供貨商,產品),不同的供貨商可以提供相同的產品,不同的銷售人員,可以銷售不同供貨商的相同產品,因此這個設計是滿足4NF的,但是這裡存在一些關係冗餘,可以將標拆為三個表(銷售人員,供貨商)(銷售人員,產品)(供貨商,產品)。第五範式主要就是消滅這種關係的冗餘,在實際應用中,沒有太多必要考慮這個。

還記得數據庫設計的六大範式嗎?一篇文章讓你完全搞懂

反模式

範式可以避免數據冗餘,減少數據庫的空間,減輕維護數據完整性的麻煩。

然而,通過數據庫範式化設計,將導致數據庫業務涉及的表變多,並且可能需要將涉及的業務表進行多表連接查詢,這樣將導致性能變差,且不利於分庫分表。因此,出於性能優先的考量,可能在數據庫的結構中需要使用反模式的設計,即空間換取時間,採取數據冗餘的方式避免表之間的關聯查詢。至於數據一致性問題,因為難以滿足數據強一致性,一般情況下,使存儲數據儘可能達到用戶一致,保證系統經過一段較短的時間的自我恢復和修正,數據最終達到一致。

需要謹慎使用反模式設計數據庫。一般情況下,儘可能使用範式化的數據庫設計,因為範式化的數據庫設計能讓產品更加靈活,並且能在數據庫層保持數據完整性。

有的時候,提升性能最好的方法是在同一表中保存冗餘數據,如果能容許少量的髒數據,創建一張完全獨立的彙總表或緩存表是非常好的方法。

另外一個比較典型的場景,出於擴展性考慮,可能會使用 BLOB 和 TEXT 類型的列存儲 JSON 結構的數據,這樣的好處在於可以在任何時候,將新的屬性添加到這個字段中,而不需要更改表結構。但是,這個設計的缺點也比較明顯,就是需要獲取整個字段內容進行解碼來獲取指定的屬性,並且無法進行索引、排序、聚合等操作


分享到:


相關文章: