前言
我們經常聽到正規化設計與反正規化設計,那麼什麼時候該遵循正規化設計?什麼時候又該違反他的規則呢?帶著這兩個問題,讓我現在帶你研究~
正規化
正規化就是前輩通過不斷的驗證給到的為了建立冗餘較小、結構合理的資料庫,是設計資料庫必須遵循的一定規則,在關係型資料庫中這種規格叫做正規化,本篇不僅說明正規化設計,也會給到一些例子,帶著各位一起分析給到的資料表設計屬於第幾正規化。
1NF 第一正規化
遵循的規則:每一列屬性都是不可再分的屬性值,確保每一列的原子性
啥玩意是不再可分?例如使用者名稱、性別、年齡聯絡方式則就是不能再分了。
但例如城市,北京市通州區,我們還是可以再分的,將一個欄位分為省:北京市 區:通州區
首先,我們看到使用者資訊表中,所在城市是可以在進行細分的。
編碼 | 使用者名稱 | 年齡 | 性別 | 聯絡方式 | 所在城市 |
---|---|---|---|---|---|
1 | 張三 | 18 | 男 | 1888888888 | 山東省青島市 |
2 | 李四 | 17 | 女 | 1999999999 | 湖北省武漢市 |
3 | 王五 | 22 | 男 | 1777777777 | 山東省青島市 |
下表我們根據上述使用者資訊表,將城市分為省和市兩個欄位,這樣設計後,該資料表則符合了第一正規化的要求。
使用者編碼 | 使用者名稱 | 年齡 | 性別 | 聯絡方式 | 所在省 | 所在市 |
---|---|---|---|---|---|---|
1 | 張三 | 18 | 男 | 1888888888 | 山東省 | 青島市 |
2 | 李四 | 17 | 女 | 1999999999 | 湖北省 | 武漢市 |
3 | 王五 | 22 | 男 | 1777777777 | 山東省 | 青島市 |
我們再以商品表做一個說明
編碼 | 商品名稱 | 價格 | 庫存 | 製造工廠 |
---|---|---|---|---|
1 | iPhone 13 白色 | 1999 | 100 | 臺灣富士康 |
2 | iPhone 12 黑色 | 1299 | 20 | 北京富士康 |
3 | iPhone 13 紅色 | 2239 | 30 | 上海英華達 |
依舊是依照上述規則,首先我們找到已無法再次分割的屬性
現在不可再分割的屬性有 編碼、價格(以只有RMB為準)、庫存,而商品名稱及製造工廠想必大家也知道,這是可以再分的屬性吧,那麼看下方符合第一正規化的資料表設計
編碼 | 品牌 | 型號 | 顏色 | 價格 | 庫存 | 製造工廠(所在城市) | 製造工廠名稱 |
---|---|---|---|---|---|---|---|
1 | iPhone | 13 | 白色 | 1999 | 100 | 臺灣 | 富士康 |
2 | iPhone | 12 | 黑色 | 1299 | 20 | 北京 | 富士康 |
3 | iPhone | 13 | 紅色 | 2239 | 30 | 上海 | 英華達 |
我們將商品名稱與製造工廠進行以下的拆分,以達到不可再分的屬性
其關係模式為:
商品名稱(品牌,型號,顏色)
製造工廠(製造工廠所在城市,製造工廠名稱)
看到這裡,想必你已經搞懂第一正規化的設計規則了,那麼我們繼續第二正規化的學習。
2NF 第二正規化
遵循的規則:首先必須符合第一正規化要求,其次一個表中只能儲存一種資料,確保每一列都與主鍵相關,我們以課程編碼為主鍵,除課程名稱以外的其他資訊與主鍵無關,所以我們只需要獨立課程編碼與課程名稱,其他則新建一張表。
課程編碼 | 課程名稱 | 講授老師 | 老師性別 | 老師聯絡方式 |
---|---|---|---|---|
10001 | C++程式設計 | 張三 | 男 | 1888888888 |
10002 | 資料結構 | 李四 | 女 | 1999999999 |
10003 | 作業系統 | 王五 | 男 | 1777777777 |
課程表
課程編碼 | 課程名稱 |
---|---|
10001 | C++程式設計 |
10002 | 資料結構 |
10003 | 作業系統 |
老師表
課程編碼 | 講授老師 | 老師性別 | 老師聯絡方式 |
---|---|---|---|
10001 | 張三 | 男 | 1888888888 |
10002 | 李四 | 女 | 1999999999 |
10003 | 王五 | 男 | 1777777777 |
這樣拆分後,我們就符合了第二正規化的要求,並且也符合第一正規化的要求,沒有可再分的屬性。
我們再以上述符合第一正規化的商品表為例
編碼 | 品牌 | 型號 | 顏色 | 價格 | 庫存 | 製造工廠(所在城市) | 製造工廠名稱 |
---|---|---|---|---|---|---|---|
1 | iPhone | 13 | 白色 | 1999 | 100 | 臺灣 | 富士康 |
2 | iPhone | 12 | 黑色 | 1299 | 20 | 北京 | 富士康 |
3 | iPhone | 13 | 紅色 | 2239 | 30 | 上海 | 英華達 |
這裡以編碼和品牌為聯合主鍵,與主鍵無關的屬性新建立一張表。
生產商表
編碼 | 製造工廠(所在城市) | 製造工廠名稱 |
---|---|---|
1 | 臺灣 | 富士康 |
2 | 北京 | 富士康 |
3 | 上海 | 英華達 |
商品表
編碼 | 品牌 | 型號 | 顏色 | 價格 | 庫存 | 生產商編碼 |
---|---|---|---|---|---|---|
1 | iPhone | 13 | 白色 | 1999 | 100 | 1 |
2 | iPhone | 12 | 黑色 | 1299 | 20 | 2 |
3 | iPhone | 13 | 紅色 | 2239 | 30 | 3 |
這樣既符合了第二正規化要求。
我們已經對第二正規化有了一個大概得了解,不要停,第三正規化在等你!
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 |
剛剛講到第三正規化一定滿足第二正規化,而第一正規化一定滿足第一正規化,那麼我們看下剛剛拆好的訂單表
- 無再可拆分的屬性,符合第一正規化。
- 無與主鍵無關屬性,符合第二正規化。
- 無傳遞依賴關係,符合第三正規化。
所以說,當你符合第三正規化時,你實際已經符合了第一第二正規化,那麼關係型資料庫的三大正規化我們就講到這裡,資料中可能有些歧義,請理解原理,勿細糾結,謝謝。
反正規化設計的目的
當然正規化只是提出的規範,但一些特殊情況下,我們要考慮的點比較多,例如
- 併發讀。
- 減少表關聯次數。
- 資料表的冗餘設計。
- 熱資料與冷資料。
- 資料的非實時性。
這裡與三大正規化做一個對比(個人見解)
- 減少表關聯次數 = 違反了第二正規化
- 資料表的冗餘設計 = 違反了第三正規化
當然也不是一概而論,這裡以訂單表為導向,來講解一下為什麼我們會迫不得已違反正規化規則。
這裡做出一個提問
使用者下單後,商品的基本資訊如果進行表關聯的方式,既訂單表的商品編碼關聯商品表的編碼,會出現什麼問題?
大概會出現這樣一個問題:
使用者購買了一臺HP印表機1999元后,商家對當前這個商品進行了修改,改為了一臺華碩筆記本,那麼通過表關聯(設符合正規化規則),使用者會不會瘋掉?
那麼如何解決這一問題?
這就使用了我上述提出的資料的冗餘設計,將商品基本資訊直接存入訂單表中,這是根據常識而定的,就跟你去商場買了一個西瓜花了20元,次日這個西瓜無論漲價還是降價,商場不會要求你補足差價,你也無法要求商場返還差價(當然這與某東買貴包賠無關,不要較勁)。
那麼在網際網路的時代,當你下單的那一時刻,你購買的商品資訊則就已經固定,無論商家是修改商品,還是刪掉商品,或者商家倒閉了關閉店鋪。你購買的商品永遠會在你的訂單內看到,當然如果商品失效,你在點選進入後,某寶可能會給到你一個快照,這個快照依舊是在你下單時儲存的資料。
你現在應該可以理解,為什麼需要反正規化,類似的例子還有很多,我在我的電商設計相關文章內有多次提出類似的需求,至此我就不一一例舉了
當然在正常情況下,你依舊需要根據三大正規化去設計你的業務,這是行業規範,只有規範統一,你才不會太“坑”你的接鍋班人。
那麼反正規化設計的優點有哪些呢?
- 提高查詢速度。
- 避免多表查詢。
- 降低資料庫的壓力。
反正規化應該注意的問題
- 過多冗餘資料導致儲存量過大。
- 必要時需配合記憶體資料庫實行。
- 違反了正規化規則,會出現插入異常、查詢異常等。
致謝
感謝你看到這裡,希望本篇可以幫助到你,謝謝。