規范化-數據庫設計原則
?
規范化
在設計和操作維護數據庫時,關鍵的步驟就是要確保數據正確地分布到數據庫的表中。 使用正確的數據結構,不僅便于對數據庫進行相應的存取操作,而且可以極大地簡化應用程序的其他內容(查詢、窗體、報表、代碼等)。正確進行表設計的正式名稱就是"數據庫規范化"。后面我們將通過實例來說明具體的規范化的工程。
?
數據冗余
數據應該盡可能少地冗余,這意味著重復數據應該減少到最少。比如說,一個部門雇員的電話不應該被存儲在不同的表中, 因為這里的電話號碼是雇員的一個屬性。如果存在過多的冗余數據,這就意味著要占用了更多的物理空間,同時也對數據的維護和一致性檢查帶來了問題,當這個員工的電話號碼變化時,冗余數據會導致對多個表的更新動作,如果有一個表不幸被忽略了,那么就可能導致數據的不一致性。
?
規范化實例
為了說明方便,我們在本文中將使用一個SAMPLE數據表,來一步一步分析規范化的過程。
首先,我們先來生成一個的最初始的表。
?
CREATE TABLE "SAMPLE" ( "PRJNUM" INTEGER NOT NULL, "PRJNAME" VARCHAR(200), "EMYNUM" INTEGER NOT NULL, "EMYNAME" VARCHAR(200), "SALCATEGORY" CHAR(1), "SALPACKAGE" INTEGER) IN "USERSPACE1"; ALTER TABLE "SAMPLE" ADD PRIMARY KEY ("PRJNUM", "EMYNUM"); Insert into SAMPLE(PRJNUM, PRJNAME, EMYNUM, EMYNAME, SALCATEGORY, SALPACKAGE) values(100001, 'TPMS', 200001, 'Johnson', 'A', 2000), (100001, 'TPMS', 200002, 'Christine', 'B', 3000), (100001, 'TPMS', 200003, 'Kevin', 'C', 4000), (100002, 'TCT', 200001, 'Johnson', 'A', 2000), (100002, 'TCT', 200004, 'Apple', 'B', 3000);?
表1-1
?
考察表1-1,我們可以看到,這張表一共有六個字段,分析每個字段都有重復的值出現,也就是說,存在數據冗余問題。這將潛在地造成數據操作(比如刪除、更新等操作)時的異常情況,因此,需要進行規范化。
?
第一范式
參照范式的定義,考察上表,我們發現,這張表已經滿足了第一范式的要求。
?
1、因為這張表中字段都是單一屬性的,不可再分;
2、而且每一行的記錄都是沒有重復的;
3、存在主屬性,而且所有的屬性都是依賴于主屬性;
4、所有的主屬性都已經定義
?
事實上在當前所有的關系數據庫管理系統(DBMS)中,都已經在建表的時候強制滿足第一范式。因此,這張SAMPLE表已經是一張滿足第一范式要求的表。考察表1-1,我們首先要找出主鍵。可以看到,屬性對<Project Number, Employee Number>是主鍵,其他所有的屬性都依賴于該主鍵。
?
從一范式轉化到二范式
根據第二范式的定義,轉化為二范式就是消除部分依賴。
考察表1-1,我們可以發現,非主屬性<Project Name>部分依賴于主鍵中的<Project Number>; 非主屬性<Employee Name>,<Salary Category>和<Salary package>都部分依賴于主鍵中的<Employee Number>;
表1-1的形式,存在著以下潛在問題:
?
1. 數據冗余:每一個字段都有值重復;
2. 更新異常:比如<Project Name>字段的值,比如對值"TPMS"了修改,那么就要一次更新該字段的多個值;
3. 插入異常:如果新建了一個Project,名字為TPT, 但是還沒有Employee加入,那么<Employee Number>將會空缺,而該字段是主鍵的一部分,因此將無法插入記錄;
?
Insert into SAMPLE(PRJNUM, PRJNAME, EMYNUM, EMYNAME, SALCATEGORY, SALPACKAGE) values(100003, 'TPT', NULL, NULL, NULL, NULL)?
?
4. 刪除異常:如果一個員工 200003, Kevin 離職了,要將該員工的記錄從表中刪除,而此時相關的Salary信息 C 也將丟失, 因為再沒有別的行紀錄下 Salary C的信息。
Delete from sample where EMYNUM = 200003
Select distinct SALCATEGORY, SALPACKAGE from SAMPLE
因此,我們需要將存在部分依賴關系的主屬性和非主屬性從滿足第一范式的表中分離出來,形成一張新的表,而新表和舊表之間是一對多的關系。由此,我們得到:
?
CREATE TABLE "PROJECT" ( "PRJNUM" INTEGER NOT NULL, "PRJNAME" VARCHAR(200)) IN "USERSPACE1"; ALTER TABLE "PROJECT" ADD PRIMARY KEY ("PRJNUM"); Insert into PROJECT(PRJNUM, PRJNAME) values(100001, 'TPMS'), (100002, 'TCT');?
表1-2
?
表1-3
?
CREATE TABLE "EMPLOYEE" ( "EMYNUM" INTEGER NOT NULL, "EMYNAME" VARCHAR(200), "SALCATEGORY" CHAR(1), "SALPACKAGE" INTEGER) IN "USERSPACE1"; ALTER TABLE "EMPLOYEE" ADD PRIMARY KEY ("EMYNUM"); Insert into EMPLOYEE(EMYNUM, EMYNAME, SALCATEGORY, SALPACKAGE) values(200001, 'Johnson', 'A', 2000), (200002, 'Christine', 'B', 3000), (200003, 'Kevin', 'C', 4000), (200004, 'Apple', 'B', 3000); Employee Number Employee Name Salary Category Salary Package 200001 Johnson A 2000 200002 Christine B 3000 200003 Kevin C 4000 200004 Apple B 3000?
CREATE TABLE "PRJ_EMY" ( "PRJNUM" INTEGER NOT NULL, "EMYNUM" INTEGER NOT NULL) IN "USERSPACE1"; ALTER TABLE "PRJ_EMY" ADD PRIMARY KEY ("PRJNUM", "EMYNUM"); Insert into PRJ_EMY(PRJNUM, EMYNUM) values(100001, 200001), (100001, 200002), (100001, 200003), (100002, 200001), (100002, 200004);?
同時,我們把表1-1的主鍵,也就是表1-2和表1-3的各自的主鍵提取出來,單獨形成一張表,來表明表1-2和表1-3之間的關聯關系:
?
表 1-4
?
這時候我們仔細觀察一下表1-2, 1-3, 1-4, 我們發現插入異常已經不存在了,當我們引入一個新的項目 TPT 的時候,我們只需要向表1-2 中插入一條數據就可以了, 當有新人加入項目 TPT 的時候,我們需要向表1-3, 1-4 中各插入一條數據就可以了。雖然我們解決了一個大問題,但是仔細觀察我們還是發現有問題存在。
?
從二范式轉化到三范式
考察表前面生成的三張表,我們發現,表1-3存在傳遞依賴關系,即:關鍵字段< Employee Number > --> 非關鍵字段< Salary Category > -->非關鍵字段< Salary Package >。而這是不滿足三范式的規則的,存在以下的不足:
?
1、 數據冗余:<Salary Category>和<Salary Package>的值有重復;
2、 更新異常:有重復的冗余信息,修改時需要同時修改多條記錄,否則會出現數據不一致的情況;
3、 刪除異常:同樣的,如果員工 200003 Kevin 離開了公司,會直接導致 Salary C 的信息的丟失。
?
Delete from EMPLOYEE where EMYNUM = 200003
Select distinct SALCATEGORY, SALPACKAGE from EMPLOYEE
因此,我們需要繼續進行規范化的過程,把表1-3拆開,我們得到:
?
表 1-5
和
?
表 1-6
?
這時候如果 200003 Kevin 離開公司,我們只需要從表 1-5 中刪除他就可以了, 存在于表1-6中的Salary C信息并不會丟失。但是我們要注意到除了表 1-5 中存在 Kevin 的信息之外, 表1-4中也存在 Kevin 的信息, 這很容易理解, 因為 Kevin 參與了項目 100001, TPMS, 所以當然也要從中刪除。
至此,我們將表1-1經過規范化步驟,得到四張表,滿足了三范式的約束要求,數據冗余、更新異常、插入異常和刪除異常。
?
在三范式之上,還存在著更為嚴格約束的BC范式和四范式,但是這兩種形式在商業應用中很少用到,在絕大多數情況下,三范式已經滿足了數據庫表規范化的要求,有效地解決了數據冗余和維護操作的異常問題。
?
結束語
在本文描述的過程中,我們通過結合實例的方法,通俗地演繹了數據表規范化的過程,并展示了在此過程中數據冗余、數據庫操作異常等問題是如何得到解決的。
在具體的工程應用中,運用數據庫規范化的方法來設計數據庫表,將是具有現實意義的。
?
參考資料
Database Normalization Basics :數據庫規范化基礎原則
Normalization principles :數據庫規范化原則和范式定義
?
?
來源: 規范化-數據庫設計原則
?
?
表規范化和非規范化的最佳實踐
?
表規范化就是通過減少它的關系直到最簡的表格。在建立一個邏輯上的關系型數據庫設計中,表規范化是一個關鍵步驟。規范化有助于避免冗余和不一致的數據;它通常是一個邏輯上的數據模式練習,整個結果在物理設計中實現。
?
部署一個規范化設計有如下目標:
1. 消除冗余數據,例如在多個表中存儲相同的數據。
2. 通過在表中只存儲相關數據來強制有效數據的依賴,并把關系數據拆分到多個相關表中。
3. 將系統在數據結構和未來增長中的靈活性最大化
?
規范化
規范化的兩到三個主要策略是:
1. 第三范式在在線交易處理(OLTP)和很多通用數據庫中使用,包括企業數據倉庫(也叫做原子倉庫)。
2. 星型模式和雪花模式是規范化的三維模式,并且在數據倉庫和 OLAP 中經常使用。
?
第三范式(3NF)
第三范式是由第一范式和第二范式中的規則組成的。下面是第三范式中的規則:
1. 消除重復組。為每個相關屬性的集合建立單獨的表,并為每個表建立一個主鍵。
2. 消除重復的列以及每個表中重復的數據。
3. 把應用到一個表中的多行柱形數據的子集,移動到不同的表中。
4. 在表之間用外鍵來建立聯系
5. 消除那些與鍵值無關的列。如果屬性不能解釋一個鍵值,那就把它們移到另外一個表中。
6. 刪除不依賴于主鍵的列
?
數據庫設計中的第一范式,第二范式和第三范式
?
下面的圖表顯示了數據庫設計的第一范式,第二范式,第三范式。
?
非規范化模式
第一范式:
為了讓非規范化模式遵守第一范式,重復的數據元素組、客戶地址行和客戶名稱被規范化到不同的表中。
?
第二范式:
這個模式要遵守第二范式就必須遵守第一范式,并且所有屬性必須完全依賴于一個組合鍵。
?
第三范式:
?
這個模式要遵守第三范式就必須消除所有傳遞依賴。當一個在非鍵值域的值取決于另一個非鍵值域,也就是非組合鍵的一部分中的值時,就發生了傳遞依賴。
?
星型模式和雪花模式
星型模式和雪花模式在數據倉庫 BI 系統中已經變得非常普遍。星型模式的基礎是從它的維度中分離出系統的事實表。維度是作為數據的屬性來定義的,比如 location 或 customer name、或部分描述、事實表參考和數據相關的具體時間。
例如,一個部分描述通常不會隨著時間流逝而變化,因此它可以定義為一個維度。與此相反,部分每日銷售是隨時間變化的,因此是事實。之所以叫做星型模式是因為它的典型特點是一個保存了隨著時間變化的大型的中央事實表,被一批維度表所環繞,其中存放著和事實表中事件條目的相關屬性。
?
雪花模式簡單的擴充了星型模式。在一個雪花模式設計中,較低基數的屬性經常從星型模式中的一個維度表移動到另外一個維度表中,并將這兩個維度表建立起關系。
?
非規范化
和規范化相比,非規范化是壓縮表數目的處理過程,因此有可能增加數據庫中的冗余數據。非規范化可以非常有效的減少復雜性或進行表連接的數目,并通過減少表的數目來減少數據庫的復雜性。非規范化的主要目的是將一個系統的性能最大化并降低系統管理的復雜度。
?
索引設計最佳實踐
?
索引對性能來說非常關鍵。數據庫使用它們以達到下列目的:
1. 應用謂詞來提高快速查詢數據在數據庫中的位置,減少查閱的行數。
2. 避免 ORDER BY 和 GROUP BY 子句產生的索引。
3. 引導連接的順序。
4. 提供 index-only 的訪問,這避免了訪問數據頁的成本。
5. 作為在關系數據庫中強制唯一性約束的唯一方法。
?
然而,索引需要額外的硬件資源:
1. 它們增加 UPDATE、INSERT、DELETE 和 LOAD 操作的額外的 CPU 和 I/O 成本。
2. 它們會增加準備時間,因為它們為優化器提供更多的選擇。
3. 他們會使用非常多的磁盤存儲。
?
在 DB2 數據庫系統中,一個 B+ 樹結構被用作實現索引的底層結構。所有數據都存儲在葉子節點,而且鍵值被隨意的鏈接進一個雙向方式中以提供雙向的索引掃描。如果指定了 DISALLOW REVERSE SCANS,那么索引不能被反向掃描(不過物理上它是和一個 ALLOW REVERSE SCANS 索引是一樣的)。
?
?
?
范式是什么
?
范式是符合某一種級別的關系模式的集合。關系數據庫中的關系必須滿足一定的要求,即滿足不同的范式。目前關系數據庫有六種范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、第四范式(4NF)、第五范式(5NF)和第六范式(6NF)。滿足最低要求的范式是第一范式(1NF)。在第一范式的基礎上進一步滿足更多要求的稱為第二范式(2NF),其余范式以次類推。一般說來,數據庫只需滿足第三范式(3NF)就行了。
?
范式的原理
?
1. 第一范式(1NF)無重復的列
?
所謂第一范式(1NF)是指數據庫表的每一列都是不可分割的基本數據項,同一列中不能有多個值,即實體中的某個屬性不能有多個值或者不能有重復的屬性。如果出現重復的屬性,就可能需要定義一個新的實體,新的實體由重復的屬性構成,新實體與原實體之間為一對多關系。在第一范式(1NF)中表的每一行只包含一個實例的信息。簡而言之,第一范式就是無重復的列。
?
說明:在任何一個關系數據庫中,第一范式(1NF)是對關系模式的基本要求,不滿足第一范式(1NF)的數據庫就不是關系數據庫。
?
2. 第二范式(2NF)屬性完全依賴于主鍵[消除部分子函數依賴]
?
第二范式(2NF)是在第一范式(1NF)的基礎上建立起來的,即滿足第二范式(2NF)必須先滿足第一范式(1NF)。第二范式(2NF)要求數據庫表中的每個實例或行必須可以被惟一地區分。為實現區分通常需要為表加上一個列,以存儲各個實例的惟一標識。
?
例如員工信息表中加上了員工編號(emp_id)列,因為每個員工的員工編號是惟一的,因此每個員工可以被惟一區分。這個惟一屬性列被稱為主關鍵字或主鍵、主碼。
?
第二范式(2NF)要求實體的屬性完全依賴于主關鍵字。所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性,如果存在,那么這個屬性和主關鍵字的這一部分應該分離出來形成一個新的實體,新實體與原實體之間是一對多的關系。為實現區分通常需要為表加上一個列,以存儲各個實例的惟一標識。簡而言之,第二范式就是屬性完全依賴于主鍵。
?
3. 第三范式(3NF)屬性不依賴于其它非主屬性[消除傳遞依賴]
?
滿足第三范式(3NF)必須先滿足第二范式(2NF)。簡而言之,第三范式(3NF)要求一個數據庫表中不包含已在其它表中已包含的非主關鍵字信息。例如,存在一個部門信息表,其中每個部門有部門編號(dept_id)、部門名稱、部門簡介等信息。
?
那么在的員工信息表中列出部門編號后就不能再將部門名稱、部門簡介等與部門有關的信息再加入員工信息表中。如果不存在部門信息表,則根據第三范式(3NF)也應該構建它,否則就會有大量的數據冗余。簡而言之,第三范式就是屬性不依賴于其它非主屬性。
?
范式的說明
?
第一范式:1NF是對屬性的原子性約束,要求屬性具有原子性,不可再分解;
?
通俗的理解是字段還可以再分嗎?如過不能,則是符合1NF的設計。
第二范式:2NF是對記錄的惟一性約束,要求記錄有惟一標識,即實體的惟一性;
?
簡單的解釋,比如你和一個女生約會建立一張表,不用每條約會記錄都記錄她的身高、體重,將身高體重單獨的存在一張表中供查詢即可。
第三范式:3NF是對字段冗余性的約束,即任何字段不能由其他字段派生出來,它要求字段沒有冗余。
打個比方,比如評論表,如果你將用戶ID,用戶頭像都放在這留言表中,就是不合適的了。用戶頭像是依賴于用戶ID,而不依賴該評論。
?
基本表的性質
?
基本表與中間表、臨時表不同,因為它具有如下四個特性:
(1) 原子性。基本表中的字段是不可再分解的。
(2) 原始性。基本表中的記錄是原始數據(基礎數據)的記錄。
(3) 演繹性。由基本表與代碼表中的數據,可以派生出所有的輸出數據。
(4) 穩定性。基本表的結構是相對穩定的,表中的記錄是要長期保存的。
?
理解基本表的性質后,在設計數據庫時,就能將基本表與中間表、臨時表區分開來。
?
參考:
?
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
