【一文秒懂】帶你徹底搞懂正規化與反正規化資料庫設計

CrazyCodes發表於2021-10-31

圖怪獸_9ef789cda64e9ae362106336d3fb4f69_18188.jpg

前言

我們經常聽到正規化設計與反正規化設計,那麼什麼時候該遵循正規化設計?什麼時候又該違反他的規則呢?帶著這兩個問題,讓我現在帶你研究~

正規化

image.png
正規化就是前輩通過不斷的驗證給到的為了建立冗餘較小、結構合理的資料庫,是設計資料庫必須遵循的一定規則,在關係型資料庫中這種規格叫做正規化,本篇不僅說明正規化設計,也會給到一些例子,帶著各位一起分析給到的資料表設計屬於第幾正規化。

1NF 第一正規化

image.png
遵循的規則:每一列屬性都是不可再分的屬性值,確保每一列的原子性

啥玩意是不再可分?例如使用者名稱、性別、年齡聯絡方式則就是不能再分了。
但例如城市,北京市通州區,我們還是可以再分的,將一個欄位分為省:北京市 區:通州區

首先,我們看到使用者資訊表中,所在城市是可以在進行細分的。
編碼使用者名稱年齡性別聯絡方式所在城市
1張三181888888888山東省青島市
2李四171999999999湖北省武漢市
3王五221777777777山東省青島市
下表我們根據上述使用者資訊表,將城市分為省和市兩個欄位,這樣設計後,該資料表則符合了第一正規化的要求。
使用者編碼使用者名稱年齡性別聯絡方式所在省所在市
1張三181888888888山東省青島市
2李四171999999999湖北省武漢市
3王五221777777777山東省青島市

我們再以商品表做一個說明

編碼商品名稱價格庫存製造工廠
1iPhone 13 白色1999100臺灣富士康
2iPhone 12 黑色129920北京富士康
3iPhone 13 紅色223930上海英華達

依舊是依照上述規則,首先我們找到已無法再次分割的屬性

現在不可再分割的屬性有 編碼、價格(以只有RMB為準)、庫存,而商品名稱及製造工廠想必大家也知道,這是可以再分的屬性吧,那麼看下方符合第一正規化的資料表設計

編碼品牌型號顏色價格庫存製造工廠(所在城市)製造工廠名稱
1iPhone13白色1999100臺灣富士康
2iPhone12黑色129920北京富士康
3iPhone13紅色223930上海英華達

我們將商品名稱與製造工廠進行以下的拆分,以達到不可再分的屬性

其關係模式為:

商品名稱(品牌,型號,顏色)
製造工廠(製造工廠所在城市,製造工廠名稱)


看到這裡,想必你已經搞懂第一正規化的設計規則了,那麼我們繼續第二正規化的學習。

2NF 第二正規化

image.png

遵循的規則:首先必須符合第一正規化要求,其次一個表中只能儲存一種資料,確保每一列都與主鍵相關,我們以課程編碼為主鍵,除課程名稱以外的其他資訊與主鍵無關,所以我們只需要獨立課程編碼與課程名稱,其他則新建一張表。

課程編碼課程名稱講授老師老師性別老師聯絡方式
10001C++程式設計張三1888888888
10002資料結構李四1999999999
10003作業系統王五1777777777

課程表

課程編碼課程名稱
10001C++程式設計
10002資料結構
10003作業系統

老師表

課程編碼講授老師老師性別老師聯絡方式
10001張三1888888888
10002李四1999999999
10003王五1777777777

這樣拆分後,我們就符合了第二正規化的要求,並且也符合第一正規化的要求,沒有可再分的屬性。


我們再以上述符合第一正規化的商品表為例

編碼品牌型號顏色價格庫存製造工廠(所在城市)製造工廠名稱
1iPhone13白色1999100臺灣富士康
2iPhone12黑色129920北京富士康
3iPhone13紅色223930上海英華達

這裡以編碼和品牌為聯合主鍵,與主鍵無關的屬性新建立一張表。

生產商表

編碼製造工廠(所在城市)製造工廠名稱
1臺灣富士康
2北京富士康
3上海英華達

商品表

編碼品牌型號顏色價格庫存生產商編碼
1iPhone13白色19991001
2iPhone12黑色1299202
3iPhone13紅色2239303

這樣既符合了第二正規化要求。

我們已經對第二正規化有了一個大概得了解,不要停,第三正規化在等你!

3NF 第三正規化

遵循的規則:要先符合第二正規化的要求,並且除主鍵列的其它列之間,不能有傳遞依賴關係。

這裡先解釋下,啥是傳遞依賴,以下列訂單表為例 ,我們通過訂單編碼可以查到商品名稱,但通過商鋪編碼也可以查詢到發貨倉及聯絡方式。既訂單編碼->發貨倉,商鋪編碼->發貨倉,這則產生傳遞依賴,通俗點講究是如果除了主鍵(訂單編碼)外,不能再有有屬性相關的非主鍵(商鋪編碼|發貨倉),我們只能通過主鍵查到所有資訊,達到獨佔的情況,意味著下條SQL語句不能讓他有效,則就達到了第三正規化的要求。

SELECT 發貨倉,店鋪電話 FROM 訂單表 WHERE 商鋪編碼 = S1
訂單編碼商品名稱商鋪編碼發貨倉店鋪電話
NS001小米手機S1某東華北發貨倉1888888888
NS002三星手機S2某貓華東發貨倉1999999999
NS003華為手機S3某多華西發貨倉1777777777

根據下述拆分達到第三正規化要求

訂單表

訂單編碼商品名稱商鋪編碼
NS001小米手機S1
NS002三星手機S2
NS003華為手機S3

商鋪表

商鋪編碼發貨倉店鋪電話
S1某東華北發貨倉1888888888
S2某貓華東發貨倉1999999999
S3某多華西發貨倉1777777777

剛剛講到第三正規化一定滿足第二正規化,而第一正規化一定滿足第一正規化,那麼我們看下剛剛拆好的訂單表

  1. 無再可拆分的屬性,符合第一正規化。
  2. 無與主鍵無關屬性,符合第二正規化。
  3. 無傳遞依賴關係,符合第三正規化。

所以說,當你符合第三正規化時,你實際已經符合了第一第二正規化,那麼關係型資料庫的三大正規化我們就講到這裡,資料中可能有些歧義,請理解原理,勿細糾結,謝謝。

反正規化設計的目的

當然正規化只是提出的規範,但一些特殊情況下,我們要考慮的點比較多,例如

  1. 併發讀。
  2. 減少表關聯次數。
  3. 資料表的冗餘設計。
  4. 熱資料與冷資料。
  5. 資料的非實時性。

這裡與三大正規化做一個對比(個人見解)

  • 減少表關聯次數 = 違反了第二正規化
  • 資料表的冗餘設計 = 違反了第三正規化

當然也不是一概而論,這裡以訂單表為導向,來講解一下為什麼我們會迫不得已違反正規化規則。


image.png
這裡做出一個提問

使用者下單後,商品的基本資訊如果進行表關聯的方式,既訂單表的商品編碼關聯商品表的編碼,會出現什麼問題?

大概會出現這樣一個問題:

image.png

使用者購買了一臺HP印表機1999元后,商家對當前這個商品進行了修改,改為了一臺華碩筆記本,那麼通過表關聯(設符合正規化規則),使用者會不會瘋掉?

image.png

那麼如何解決這一問題?

這就使用了我上述提出的資料的冗餘設計,將商品基本資訊直接存入訂單表中,這是根據常識而定的,就跟你去商場買了一個西瓜花了20元,次日這個西瓜無論漲價還是降價,商場不會要求你補足差價,你也無法要求商場返還差價(當然這與某東買貴包賠無關,不要較勁)。

image.png

那麼在網際網路的時代,當你下單的那一時刻,你購買的商品資訊則就已經固定,無論商家是修改商品,還是刪掉商品,或者商家倒閉了關閉店鋪。你購買的商品永遠會在你的訂單內看到,當然如果商品失效,你在點選進入後,某寶可能會給到你一個快照,這個快照依舊是在你下單時儲存的資料。

你現在應該可以理解,為什麼需要反正規化,類似的例子還有很多,我在我的電商設計相關文章內有多次提出類似的需求,至此我就不一一例舉了

當然在正常情況下,你依舊需要根據三大正規化去設計你的業務,這是行業規範,只有規範統一,你才不會“坑”你的接班人。


那麼反正規化設計的優點有哪些呢?

  1. 提高查詢速度。
  2. 避免多表查詢。
  3. 降低資料庫的壓力。

反正規化應該注意的問題

image.png

  1. 過多冗餘資料導致儲存量過大。
  2. 必要時需配合記憶體資料庫實行。
  3. 違反了正規化規則,會出現插入異常、查詢異常等。

致謝

感謝你看到這裡,希望本篇可以幫助到你,謝謝。

相關文章