資料庫正規化是為解決關聯式資料庫中資料冗餘、更新異常、插入異常、刪除異常問題而引入的。簡單的理解,資料庫正規化可以避免資料冗餘,減少資料庫的空間,並且減輕維護資料完整性的麻煩。
第一正規化(1NF)
第一正規化,強調屬性的原子性約束,要求屬性具有原子性,不可再分解。
舉個例子,活動表(活動編碼,活動名稱,活動地址),假設這個場景中,活動地址可以細分為國家、省份、城市、市區、位置,那麼就沒有達到第一正規化。
第二正規化(2NF)
第二正規化,強調記錄的唯一性約束,表必須有一個主鍵,並且沒有包含在主鍵中的列必須完全依賴於主鍵,而不能只依賴於主鍵的一部分。
舉個例子,版本表(版本編碼,版本名稱,產品編碼,產品名稱),其中主鍵是(版本編碼,產品編碼),這個場景中,資料庫設計並不符合第二正規化,因為產品名稱只依賴於產品編碼。存在部分依賴。所以,為了使其滿足第二正規化,可以改造成兩個表:版本表(版本編碼,產品編碼)和產品表(產品編碼,產品名稱)。
第三正規化(3NF)
第三正規化,強調屬性冗餘性的約束,即非主鍵列必須直接依賴於主鍵。
舉個例子,訂單表(訂單編碼,顧客編碼,顧客名稱),其中主鍵是(訂單編碼),這個場景中,顧客編碼、顧客名稱都完全依賴於主鍵,因此符合第二正規化,但是顧客名稱依賴於顧客編碼,從而間接依賴於主鍵,所以不能滿足第三正規化。為了使其滿足第三正規化,可以拆分兩個表:訂單表(訂單編碼,顧客編碼)和顧客表(顧客編碼,顧客名稱),拆分後的資料庫設計,就可以完全滿足第三正規化的要求了。
值得注意的是,第二正規化的側重點是非主鍵列是否完全依賴於主鍵,還是依賴於主鍵的一部分。第三正規化的側重點是非主鍵列是直接依賴於主鍵,還是直接依賴於非主鍵列。
反模式
正規化可以避免資料冗餘,減少資料庫的空間,減輕維護資料完整性的麻煩。
然而,通過資料庫正規化化設計,將導致資料庫業務涉及的表變多,並且可能需要將涉及的業務表進行多表連線查詢,這樣將導致效能變差,且不利於分庫分表。因此,出於效能優先的考量,可能在資料庫的結構中需要使用反模式的設計,即空間換取時間,採取資料冗餘的方式避免表之間的關聯查詢。至於資料一致性問題,因為難以滿足資料強一致性,一般情況下,使儲存資料儘可能達到使用者一致,保證系統經過一段較短的時間的自我恢復和修正,資料最終達到一致。
需要謹慎使用反模式設計資料庫。一般情況下,儘可能使用正規化化的資料庫設計,因為正規化化的資料庫設計能讓產品更加靈活,並且能在資料庫層保持資料完整性。
有的時候,提升效能最好的方法是在同一表中儲存冗餘資料,如果能容許少量的髒資料,建立一張完全獨立的彙總表或快取表是非常好的方法。舉個例子,設計一張“下載次數表”來快取下載次數資訊,可使在海量資料的情況下,提高查詢總數資訊的速度。
另外一個比較典型的場景,出於擴充套件性考慮,可能會使用 BLOB 和 TEXT 型別的列儲存 JSON 結構的資料,這樣的好處在於可以在任何時候,將新的屬性新增到這個欄位中,而不需要更改表結構。但是,這個設計的缺點也比較明顯,就是需要獲取整個欄位內容進行解碼來獲取指定的屬性,並且無法進行索引、排序、聚合等操作。因此,如果需要考慮更加複雜的使用場景,更加建議使用 MongoDB 這樣的文件型資料庫。
(完)
更多精彩文章,盡在「服務端思維」微信公眾號!