文章目錄
前言:
上一章我們看了數據庫設計的一整套方法,今天呀,我們來介紹一下範式和反範式以及通過一個實例來看一下數據庫的設計,其實範式也是屬於邏輯設計
一、範式理論
1.、什麼是範式
滿足不同程度的要求爲滿足不同的範式
把屬性放置在正確的實體的這個過程稱爲範式化(normalization)
發展歷史
- -1971~1972:Codd系統地提出了1NF、2NF和3NF的概念,討論了規範化問題
- 1974: Codd和Boyce共同提出了新範式,BCNF
- 1976: Fagin提出了4NF
- 之後的研究人員進一步提出5NF
遵循規範化理論設計出的關係數據模型
- 能夠避免冗餘數據的產生;
- 降低數據不一致的風險;
- 模型具有良好的可擴展性;
- 可以靈活調整以反映出不斷變化的業務規則。
2、範式之間的關係
範式之間的關係:
- 滿足最低要求的叫第一範式,記爲1NF。
- 在第一範式滿足進一步要求的爲第二範式,2NF。
- 以此類推。
- 一個低一級範式的關係模式通過模式分解(Schema Decomposition)可以轉換爲若干個高一級範式的關係模式的集合。---->比如第二範式通過模式分解,生成若干個第三範式關係模式,這種過程就叫做範式化。
3、值域
- 定義一個屬性取值的有效範圍
- 在值域裏面的值都是合法數據。
- 值域體現了規則。
4、第一範式(1NF)
- 屬性取值的原子性(不可再分)。
- 對原子性的理解很容易出現分歧,比如身份證裏面就包含了出生日期,性別的屬性,那是否需要拆分呢?按照理論上來說它是可以拆分的,不具備原子性。但從值域的角度來講,在身份證這個值域裏面它具備了原子性就不用繼續拆分了。
- 屬性取值數量是單一的,不能是值域裏面的子集。
- 需要有主鍵。
- 實體中的屬性不存在重複組問題。
問題:
1.數值格式不統一不說了,還包含非數值的字符
2.更大的問題是,有兩個人的電話號碼存放的電話數量超過一個。也就是違反了“屬性取值數量是單一的,不能是值域裏面的子集”這種情況。兩個號碼是電話號碼值域裏面的子集合。
上面的表示比較常見的拆分手段,實際上還是不符合第一範式。因爲出現了repeating group,重複組問題
Repeating group,技術上講取值是原子性的,但在概念上把相同的屬性進行了重複
Repeating group所產生的問題
- 有些記錄會產生空值。(實際應用場合,這種大寬表會帶來數據的稀疏性,例如數據挖掘的寬表使用)
- 結構會產生不穩定性,比如有些人有3個電話號碼,甚至更多。所以可能要經常更新表結構,導致模型的不穩定性
也就是實際應用中常說的會因爲業務的發展而對模型帶來不穩定性衝擊 - 這個也會在使用數據的時候產生歧義,那個手機號碼應該放在第一列,那個手機號碼放在第二位,規則是什麼,要獲取客戶的聯繫方式的時候以那個電話爲準?
導致業務使用數據的時候會有語義上的混亂和不明確。
那麼應該怎麼辦呢?
這個就ok!!!
5、第二範式(2NF)
第二範式的兩個必要條件:
-
首先要滿足第一範式。
-
每一個非主屬性都完全函數依賴於任何一個候選鍵。
-
第2範式強調的是完全函數依賴。
-
簡單的理解2NF就是所有非主鍵字段都要依賴於整個主鍵,而不是其中的一部分
-
簡單的來說, 如果一個實體的主鍵字段只有一個,那麼基本上這個實體就是符合第二範式的
-
對於不滿足2NF比如訂單日期。實際上它依賴於部分主鍵,訂單編號,所以在這個表裏面,會隨着訂 - 單編號的重複而出現大量的重複。數據冗餘了。
那麼怎麼修改呢?
修改方法:
6、第三範式(3NF)
- 首先要滿足第二範式。
- 每一個非主屬性不會傳遞性依賴於鍵碼。
簡單的理解3NF就是所有非主鍵字段都要依賴於整個主鍵,而不會依賴於非主鍵的其他屬性
我們就拆表!
拆表,利用外鍵形成關係
7、其他範式
理解:
1NF: 要有主鍵。2NF: 依賴於整個主鍵。3NF: 只能依賴於主鍵
因爲在實際應用中,模型做到滿足第三範式就已經足夠了,現在數據庫設計最多滿足3NF,普遍認爲範式過高,雖然具有對數據關係更好的約束性,但也導致數據關係表增加而令數據庫IO更易繁忙,
所以在現實項目中,基本沒有實現到3NF以上級別的案例。所以在培訓過程中,不用介紹3NF之後的範式標準了,有興趣的學員,可以課後自行查看相關資料學習
BCNF,4NF,5NF就是主鍵加強。
BCNF:符合3NF,並且,主屬性不依賴於主屬性。
4NF:要求把同一表內的多對多關係刪除。
5NF:從最終結構重新建立原始結構
8、雪花模型
雪花模型是符合三範式要求的。所以作爲一個擴展知識的點簡單介紹。
9、注意事項
-
建立命名規則:
命名規則的意義:
• 統一命名,避免歧義。
• 防止冗餘的實體或者屬性產生。
• 有利於工作中不同角色的人員之間通過規範的命名和屬於進行交流。
• 便於使用。實體和屬性的命名建議:
• 實體名稱:分類域大寫+實體描述詞(全稱,首字母大寫)。
• 屬性名稱:使用全稱,首字母大寫,一些約定俗稱的空格縮寫。
• 避免英語和拼音的混用。
• 如果是縮寫,一定是英語的縮寫,避免使用拼音的聲母縮寫。
命名規則最主要的思想還是要統一,命名統一纔能有利於大家交流和規範開發
-
按照設計流程設計邏輯數據模型
-
確定實體和屬性:
定義實體的主鍵(PK)。
定義部分非鍵屬性(Non-Key Attribute)。
定義非唯一屬性組。
添加相應的註釋內容。 -
確定實體與實體之間的關係
通過外鍵來體現。
決定實體之間是否是可識別的關係。
確定關係的基數屬於1:1, 1:n還是n:m。 -
補充實體的非鍵值屬性
按照3NF的規則,判定添加的屬性是否符合3NF的設計原則。
如果新增屬性違反3NF,需要進行實體拆分,確定新的實體和關係。
添加註釋。
二、物理設計
1、物理設計
-
在用戶確認的邏輯模型基礎上,以數據庫系統運行效率,業務操作效率,前端應用效率等因素爲出發點對模型進行的調整。
-
面向物理實施過程的具體細節。
-
最終目的是轉化爲目標數據庫的可部署的定義語言(DDL)。
-
工作內容,包括但不限於
- 實體非正則化處理;
- 表和字段的物理命名;
- 確定字段的類型,長度,精度,大小寫敏感等屬性;
- 增加邏輯模型中不存在的物理對象:索引,約束,分區等。
2、相信的事務不同的名稱
操作型文件系統 | 關係型理論 | 邏輯模型 | 物理模型 |
---|---|---|---|
文件(File) | 關係(Relation) | 實體(Entity) | 表(Table) |
行記錄(Record) | 元組(Tuple) | 實例(Instance) | 行(Row) |
列記錄(Field) | 屬性(Attribute) | 屬性(Attribute) | 字段(Column) |
3、邏輯模型和物理模型對比(重點!!)
LDMvs PDM
邏輯模型 | 物理模型 | |
---|---|---|
包含內容 | 實體、屬性 | 表,字段 |
鍵值 | 主鍵 | 索引,唯一性約束 |
名稱定義 | 業務名稱 | 物理命名(受到數據庫產品限制) |
正則化 | 符合3NF | 依據性能進行非正則化處理 |
冗餘數據 | 無冗餘數據 | 含冗餘數據 |
派生數據 | 無派生數據 | 含派生數據 |
面向用戶 | 業務人員和建模人員 | DBA和應用開發人員 |
鍵值:物理模型一般不使用PRIMERY KEY,更多的使用UNIQUE+NOT
NULL約束來實現。因爲用主鍵約束對數據質量過高,所以在物理實現上,一般會降低約束性要求,主鍵更多的反映在邏輯概念上。
4、物理模型反範式處理
從性能和應用需求出發
- 物理模型是以性能爲出發點,支持應用需求,兼顧數據庫物理限制。
- CPU無限快,內存無限多,存儲無限大,帶寬無限寬,還有必要反範式處理麼?
有限的資源,有限的硬件條件提出了物理模型反範式化的需求。
反範式化:反範式處理也叫非正則化處理。 就是和範式化過程相反的過程和技術手段。把模型從第三範式降級到第二範式,或者第一範式的過程。
反範式處理需要適度進行
- 對於特定配置的硬件系統,在滿足應用功能目標和性能指標的前提下,適度進行。
- 帶來數據冗餘問題。
- 有可能會導致數據不一致問題。
反範式例子1:
增加冗餘列,避免頻繁發生表關聯操作(Join)
反範式例子2:
增加冗餘列,利用repeating group來減少SQL的複雜度。
在前端報表應用中爲了便於報表展現而採用的縱橫轉換。
反範式例子3:
增加派生列,減少函數計算
5、反範式常見手段
常見反範式化處理方式
- 增加重複組(repeating groups)------>例子2
- 預關聯(pre-joins)----->例子1
- 派生字段------>例子3
- 建立彙總表或臨時表
- 表拆分(水平拆分或者垂直拆分)
影響
- 並非對所有處理過程都能帶來性能提升,有些負面影響需要綜合考慮進行平衡。
- 反範式會降低數據模型的靈活性。
- 帶來數據不一致的風險。
6、維護數據完整性
反範式處理後增加了數據冗餘性,需要一定的管理措施來維護數據完整性。
批處理維護
- 批處理維護是指對複製列或派生列的修改積累一定的時間後,運行一批處理作業或存儲過程對複製或派生列進行修改,這隻能在對實時性要求不高的情況下使用。
批處理的方法是集中時間點運行批量處理作業,所以時效性不高,數據庫內數據在一定時間範圍內,存在有可能存在數據不一致情況;
應用邏輯
- 在應用實現過程中,在同一事務中對所有涉及的表進行增、刪、改操作。
- 風險較大,容易遺漏,特別是在需求變化時,不易於維護。
應用邏輯如果出現bug,很容易造成冗餘數據不一致情況,比如update A表數據之後忘記update B表裏面冗餘的數據了。
觸發器
- 實時處理性高。
- 但對於數據庫壓力較大,尤其是高併發環境,觸發器數量需要嚴格控制。
觸發器實時性處理效果好,應用更新A表數據後,數據庫自動觸發去更新B表數據。但是觸發器的代價就是會造成數據庫壓力
7、對象命名規範示例
對象 | 前綴 | 範例 | 說明 |
---|---|---|---|
表 | t_ | t_tablename | t_表名 |
普通視圖 | v_ | v_viewname | v_視圖名 |
索引 | ix_ | ix_tablename_columnname | 這是最常用的索引,用ix_表示。如果表名或字段名過長,則用表名和字段名的縮寫表示,儘量使用通用縮寫或去元音的縮寫方式。 |
觸發器 | trg_ | trg_triggername | trg_觸發器名 |
存儲過程 | p_ | p_procedurename | p_存儲過程名 |
函數 | f_ | f_functionname | f_函數名 |
8、表的物理化
進行反範式化操作。
- 決定是否要分區。
- 對於大表進行分區,減少IO掃描量,加速範圍查詢。
- 決定是否要拆分歷史表和當前表。
- 歷史表是冷數據,可以放在低速存儲上;當前表是熱數據,使用高速存儲。
- 歷史表可以使用壓縮方法減少佔用的存儲空間。
9、字段的物理化
- 對字段選擇合適的類型,包括
儘量使用短字段的數據類型。
使用一致的數據類型。
選擇高效數據類型。 - 字段的約束
- DEFAULT
如果能夠從業務層面補全字段值,就不建議使用DEFAULT約束,避免數據加載時產生不符合預期的結果。 - NOT NULL
給明確不存在NULL值的字段加上NOT NULL約束。 - 唯一約束/主鍵約束
主鍵 = 唯一 + NOT NULL。
如果條件允許,就增加。
檢查約束
檢查約束因爲對於數據質量提出了要求,不滿足約束的數據在插入數據表會導致SQL失敗。
10、索引的創建和使用
可以增加索引的情況:(是建議)
- 在經常需要搜索查詢的列;
- 在作爲主鍵的列上創建索引,強制該列的唯一性;
- 在經常使用連接的列上創建索引;
- 在經常需要根據範圍進行搜索的列上創建索引;
- 在經常需要排序的列上創建索引;
- 在經常使用WHERE子句的列上創建索引。
BUT!
索引建多了,會有負面影響
- 佔用更多的空間;
- 插入基表數據的效率會下降。
- 刪除無效的索引,避免空間浪費
11、其他物理化手段
根據其他特定需求:
- 是否採用壓縮。
- 是否需要對數據進行加密。
- 是否需要對數據進行脫敏。
三、數據庫設計案例
1.、邏輯模型設計
場景客戶下單購買設備,這是一個訂單表的樣例,客戶股買設備後,訂單裏面填寫相關信息。
可提取的屬性列表:
這些屬性中有重複的數據(有repeating group,連第一範式都不符合)
那麼該怎麼辦呢?
---------->就要消除重複組情況(正則化處理)
消除repeating groups後,現在符合第一範式
目前存在問題是部分依賴
---------->所以要進行第一範式向第二範式轉換(正則化處理——消除依賴部分主鍵)
消除部分依賴型後,現在符合第二範式。
目前存在什麼問題?下一步應該如何處理?
------->現在存在的問題是客戶信息依賴與客戶編號,而客戶編號依賴於訂單編號,這種依賴有傳遞性,並不直接依賴。
所以第二範式向第三範式轉換,需要消除這種傳遞依賴關係。
消除傳遞性依賴後,現在符合第三範式。
邏輯模型基本完成。
3NF模型 - 數據示例
2、物理模型設計
1、數據類型和長度
-
前面完成3NF的邏輯模型設計之後,開始進行物理模型設計。
-
首先是按照一定的規範對錶名和字段名命名,避免使用數據庫關鍵詞,一定的大小寫規範。
-
另外就是確定字段級別的數據類型,如果牽涉到字符字段定義的長度,那麼根據實際數據可能地值域確定上限範圍。
-
最後就是確定每個字段是否要增加約束,NOT NULL, UNIQUE的約束
2、反範式化
3、索引選擇
以Order , Order_Item爲例,增加索引沒有標準答案,還是要根據實際需求場景和數據量來判斷