數據庫範式的三個應用[網絡]

規範化爲什麼重要?目前很多的數據庫由於種種原因還沒有被規範化。本文中解釋了其中一些原因,並用不同形式的範式(normal form)規範化了一個保險公司的理賠表。在這個過程中表的改變以及添加的一些附加表使數據庫效率更高、錯誤更少、更容易維護。

  數據庫的規範化是優化表的結構和把數據組織到表中的實踐,這樣做數據才能更明確。規範化使你能夠改變業務規則、需求和數據而不需要重新構造整個系統。

  通過改變存儲數據的方式--僅僅改變一丁點--並改變訪問這些信息的程序,你就可以消除很多錯誤或垃圾數據出現的機會並減輕更新信息所必要的工作量。

  公司現實存在的一個問題可以用一句話概括"我們一般都這樣做"。我們一般像採用那種方式存儲信息;我們一般允許人們把任何信息寫入<insert field name>;我們一般採用那種方式編程。這通常是一件壞事,特別是對於年輕的和正在學習的公司來說。但是,當有新的系統和更好的完成任務的途徑的時候,有時"採用那種方式任務完成得很好"這句話可能需要重新探討和修改。規範化數據就是公司常常採用的有益的方式之一。

  儘管對於COBOL程序(例如任何COBOL程序員都熟悉的文件佈局)使用數據來說,把它們(數據)存儲在關係數據庫中與存儲在平面文件中很相似,但是存儲在平面文件中的方法並不是完成任務的必要的最好的途徑,特別是由於你不瞭解兩者之間的差別或害怕改變,而簡單地把過去的觀念帶入到現在的方式。

  注意:Dictionary.com是這樣定義規範化的:"使其標準,特別使導致它符合某種標準或規範。"或"某種標準的強制接受"。Webopedia認爲規範化是"在關係數據庫設計中,組織數據以最小化冗餘的過程。規範化通常包括把一個數據庫分成兩個或多個表並定義表之間的關係。其目標是隔離數據,這樣添加、刪除和修改某個字段只需要在一個表中進行,接着可以通過定義的關係傳遞到數據庫中剩餘的表中"。我更喜歡這個定義。

  術語

  在你瞭解現實世界中的一個保險公司的例子之前,你需要了解一些在討論中會用到的術語。處理數據庫的時候,特別是在處理規範化問題的時候,下面一部分講到的一組新的關鍵字很有作用:

  · 關係(Relation):從本質上說,關係是一個包含行和列的二維表或數組。

  · 關聯(Relationship):關聯是不同表之間的數據彼此聯繫的方法。關聯同時存在於形成不同實體的數據項之間和表實體本身之間,構成了數據庫規範化的基本核心問題。數據關聯有三種基本的類型,對它們有所瞭解是很重要的:

   一對一(1:1):一對一關聯意味着任何給定的每個(而不是大多數)實例嚴密地與另一個實體的一個實例對應。每個人只有一個正確的指紋就是唯一的。每個電話號碼準確地與一個付帳的獨立私人客戶對應(不是公司)。美國的每個人都只有一個社會保障號碼。

   一對多(1:M):一對多關聯意味着給定實體的一個實例可以可以與另一個實體的零個實例、一個實例或者多個實例關聯。每個人可能沒有小孩、有一個小孩或多個小孩。每個人可能沒有汽車、有一輛汽車或多輛汽車。
 
   多對多(M:N):多對多關聯(給定實體的零個、一個或多個實例與另一個實體的零個、一個或多個實例關聯)是一種直接模擬很複雜的關聯,它經常被分解爲多個1:M關聯。由於多個家庭混合在一起,一個或多個小孩可能沒有父母親(孤兒)、一個父母(單親家庭),多於一個父母(兩個仍然在一起或者離婚的兩個父母、或者離婚了又復婚了的父母)。房屋或財產可以轉讓給一個人或多個人,而這些人(一個或多個)在遺囑上可能又一個或多個房屋或財產。

  · 屬性(Attribute):屬性被認爲是程序或數據庫中的某些組件的可以修改的特性或特徵,它可以被設置爲不同值或者關係或表中的列。

  · Tuple:Tuple是關係數據庫或非關係數據庫中的排序了的一組值或值屬性:關係中的一行。

  · 刪除異常:刪除異常指由於其它數據故意的刪除而導致的數據矛盾或未預料到的數據(信息)丟失。

  · 插入異常:插入異常指由於數據的缺少或缺乏導致沒有能力把信息添加到數據庫。

  · 更新異常:更新異常指由於數據冗餘或者冗餘數據的不完整更新造成的數據矛盾。

  · 關係的分解:關係的分解指把一個關係分解成多個關係,從而使關係符合更高的範式。

  · 數據冗餘:數據冗餘指數據庫中沒有必要的數據重複。

  · 數據完整性:數據完整性指數據庫中數據的一致性。保證數據完整性很重要,只有這樣用戶才知道他們依賴的數據是正確的、他們查詢的結果以及程序纔是精確的和符合期望的。

  · 原子值:原子值是一個值,它既不是能被進一步拆分的一組值,也不是一個重複的組。每個列都有一個完整的值,但是隻有一個值--這個值不能被分解爲多個部分,它要麼被數據庫使用,要麼被使用數據庫的用戶訪問的信息。

  · 參考完整性規則:參考完整性規則指存儲在非空的外部健中的值必須是某種關係中的關鍵數據項。

  · 外部健:外部健是一個關係中的一組屬性(一個或多個列),它同時也是某種(相同的或其它的)關係中的主鍵。它是關係之間的邏輯鏈接。參考自己關係的外部健稱爲遞歸外部健。

  · 功能依賴:功能依賴意味着一行中某個屬性的值由該行中另一個屬性的值決定。這通常出現在主鍵(使某行唯一的信息片斷)與該行的其它信息之間。城市和州的組合依賴於Zip(郵政)代碼,即使給定的一個州中有很多Zip代碼與某個城市關聯。美國的每個合法的人員身份依賴於他的社會保障號碼。

  · 決定性:功能依賴左邊的屬性決定行中其它屬性的值(Zip代碼決定了城市和州;社會保障號碼決定了人的身份;執照號碼和州決定了汽車的擁有者)。

  · 實體完整性規則:實體完整性規則指某一行的關鍵屬性可能爲空(如果你在某個城市就有一個Zip代碼;如果你有一輛汽車就有一個執照號碼)。

  · 約束:約束是一種規則,它限定了數據庫中的值。電話號碼必須是數字的;美元數量必須是數字的;state必須是合法的州或省;country必須是合法的國家;日期不能是2月31號。

  現在你已經知道了很多相關的術語了,我們可以看看相關術語中規範會的意義了。下面的例子並不是典型的僱員―經理―部門示例,也不是學生―教授―課程提供示例。我將演示一個假設的保險公司的數據庫。數據庫中的表比本示例中用到的要複雜得多,但是與人們遇到的比較相近。

  圖1顯示了理賠(claim)表的非規範化定義。儘管在某個保險公司的數據庫中的表比它多得多,但是這些表爲我們提供了一些背景,通過它我們可以看到規範化和其分支。請記住每個章節中的示例都只有部分列,這樣就簡化了示例並使你輕易地看到發生變化的東西。

CLAIM_NUM、 OCCURANCE_NUM 、 CLAIM_STATUS、 ACCDNT_YR、 ACCDNT_DT、 REPORTED_DT、 ENTERED_DT、 CLAIM_DT1、 CLAIM_DT2、 CLAIM_DT3 、 CLAIM_DT4、 CLAIM_DT4 、 CLAIM_DT5 、 CLAIM_DT6 、 CLAIM_DT7、 CLAIM_DT8 、 CLAIM_DT9 、 CLAIM_DT10、 CLOSED_DT 、 DEATH_DT、 ASSIGNED_DT、 ADJSTER_CD 、ADJUSTER_NAME 、 AGENT_CD 、 AWARD_CD 、 CAUSE_CD 、 CAUSE_DESC、 LOCATION 、 SITE 、 COVERAGE_CD 、 COVERAGE_DESC、 DED_RECOV、 DEDUCTIBLE_REMAIN 、 PAID_1 、 RESERVED_1 、 PAID_2 、 RESERVED_2 、 PAID_3 、 RESERVED_3 、 PAID_4 、 RESERVED_4 、 PAID_5 、 RESERVED_5 、 PAID_6 、 RESERVED_6 、 PAID_7 、 RESERVED_7 、 PAID_8 、 RESERVED_8、 PAID_9 、 RESERVED_9 、 PAID_10 、 RESERVED_10 、 LEGAL_FLG、 KEY1、 KEY2、 KEY3、 KEY4、 KEY5、 KEY6、 KEY7、 KEY8、 KEY9、 KEY10、 SEVERITY_CD 、 POLICY_NUM 、 PAYMENT_NUM 、 SSN、 STATE、 ACTVY_DT、 ENTRY_DT、 ADMIN_CD、ADMIN_DESC、 REOPEN_DT、 INSURED_NAME、 INSURED_ADDRESS、 INSURED_PHONE、 INSURED_CITY、 INSURED_STATE、 INSURED_ZIP、 CLAIMANT_NAME、 CLAIMANT_ADDRESS、 CLAIMANT_CITY、 CLAIMANT_STATE、 CLAIMANT_ZIP、 CLAIMANT_PHONE、 SPECIAL_DT_1 、 SPECIAL_DT_2、 SPECIAL_DT_3、 SPECIAL_DT_4 、 SPECIAL_DT_5、 SPECIAL_DT_6 、 SPECIAL_DT_7 、SPECIAL_DT_8 、SPECIAL_DT_9 、 SPECIAL_DT_10 、 GROSS_PD、 POLICY_ID

圖1:未規範化的理賠表的列


  第一範式(1NF)

  把數據庫或數據庫的錶轉換爲第一範式一般都相當簡單。第一範式要求消除數據中重複的組,這是通過建立相關數據的單獨表來實現的。它通過觀察數據和表結構來確定表以完成第一範式。

  第一範式是通過把重複的組放到每個獨立的表中,把這些表通過一對多關聯聯繫起來這種方式來消除重複組的。

  沒有重複的屬性以及沒有重複的一組值--這聽起來足夠簡單了。但是,有時候由於沒有其它的選擇,使人們相信只有簡單地給設計添加任何其它集合卻很困難,但是這也是你所做的事情。

  如果我們想使理賠表達到第一範式,我們就需要找到真正與某個理賠相關聯的所有屬性。到底是什麼構成了理賠?

  · 理賠要有編號。

  · 理賠要有提出要求的人。

  · 理賠要有報告日期。

  · 理賠要有事故或生病日期。

  · 理賠要有由於事故或者生病引起的某種物品保留的數量。

  · 理賠屬於或者依據某種策略編寫。

  · 理賠能夠結束。

  · 理賠能夠重新開始。

  · 理賠有某種覆蓋面嗎?或者某種策略有更多的的事情?

  · 理賠有起因嗎?或者事故或生病有起因嗎?

  · 支付了理賠嗎?或者支付了發票嗎?

  · 理賠有社會保障號碼嗎?或者有時候某個社會保障號碼屬於提出要求的人嗎?

  · 死亡日期是個有趣的部分。理賠的人死亡了嗎?沒有,但是如果是生命保險,它可能與理賠相關,因此應該留着。

  修改與理賠直接相關的列,得到的結果如圖2所示:

CLAIM_NUM、 CLAIM_STATUS、 ACCIDENT_YR、 ACCIDENT_DT、 REPORTED_DT、 ENTERED_DT、 CLOSED_DT、 DEATH_DT、 ASSIGNED_DT、 ADJSTER_CD、 ADJUSTER_NAME、 AGENT_CD、 AGENT_NAME、 AWARD_CD、 AWARD_DESC、 PAYMENT_NUM、 LOCATION、 SITE、 DEDUCTIBLE_RECOVER、DEDUCTIBLE_REMAIN、 POLICY_NO、 POLICY_DESCRIPTION、 STATE、 RUN_DT、 ACTIVITY_DT、 ENTRY_DT、 REOPEN_DT、 INSURED_NAME、 INSURED_ADDRESS、 INSURED_PHONE、 INSURED_CITY、 INSURED_STATE、 INSURED_ZIP、 CLAIMANT_NAME、 CLAIMANT_ADDRESS、 CLAIMANT_CITY、 CLAIMANT_STATE、 CLAIMANT_ZIP、 CLAIMANT_PHONE、 GROSS_PD

圖2:第一範式的理賠表

符合第一範式的理賠表修訂版本將包含僅僅與理賠相關的信息,沒有包含支付或發票、策略或事故。

Payment_numClaim_statusAccident_dtAccident_yrReported_dt Entered_dt
123456789 Open 20-JUN-2000200028-JUN-2000 29-JUN-2000
234567890Reviewed 15-FEB-1984 1984 19-FEB-1984 20-FEB-1984
147258369Reopened 08-APR-2003 2003 10-APR-2003 11-APR-2003
258369147Closed 18-DEC-19801980 18-DEC-1980 19-DEC-1980

  如果你有支付表,並且存儲了特定理賠的保留數量以供支付其它不同的帳單,爲什麼不把它們存儲在支付表中呢?總之,你在支付表中存儲了一些信息,因此爲什麼不把這些內容也放在它裏面而不要放在理賠表中呢?

  如果把這些信息放入理賠表的唯一原因是某個用戶在理賠時可能需要這些信息,那麼理賠表和支付表可以連接(join)起來,而且信息可以來自單個理賠發生的所有支付總和。並且由於你擁有不同類型的保險策略(因此有不同類型的理賠),爲什麼不把所有類型的理賠的支付信息存儲在一張表中呢?把所有的支付信息存儲在相同的表中符合邏輯。與某種支付(屬性)相關聯的大多數信息是相同的,不管是那種類型的支付或那種類型的理賠。但是,不同類型的理賠的帳號信息有些不同。

  
第二範式(2NF)

  第二範式處理冗餘數據的刪除問題。當某張表中的信息依賴於該表中其它的不是主鍵部分的列的時候,通常會違反第二範式。

  如果新的第一範式理賠表的列如下,那麼可以迅速、輕易看到的冗餘數據就是被保險人的城市和州和提出理賠要求的人的城市和州。城市和州都直接依賴於Zip代碼,而不依賴於與理賠相關的任何東西。

CLAIM_NUM、 CLAIM_STATUS、 ACCIDENT_YR、 ACCIDENT_DT、 REPORTED_DT、 ENTERED_DT、 CLOSED_DT、 DEATH_DT、 ASSIGNED_DT、 ADJSTER_CD、 ADJUSTER_NAME、 AGENT_CD、AGENT_NAME、 AWARD_CD、 AWARD_DESC、 LOCATION、 SITE、 DEDUCTIBLE_RECOVER、 DEDUCTIBLE_REMAIN、 POLICY_NO、 POLICY_DESCRIPTION、STATE、 RUN_DT、 ACTIVITY_DT、 ENTRY_DT、 REOPEN_DT、 INSURED_NAME、 INSURED_ADDRESS、 INSURED_PHONE、 INSURED_CITY、 INSURED_STATE、 INSURED_ZIP、 CLAIMANT_NAME、 CLAIMANT_ADDRESS、 CLAIMANT_CITY、 CLAIMANT_STATE、 CLAIMANT_ZIP

圖3.第二範式的Claim

Claim_numClaimant_name Claimant_addressClaimant_cityClaimant_stateClaimant_zip
123456789Jennifer Smith1234 MainPittsburghPA 15201
234567890Bill Smith7852 Eagle PittsburghPA 15202
147258369 John Jones4562 EdgeEighty Four PA 15330
258369147 Eleanor Stillwater7531 West EasternSomersetPA 15510

Zip_CodeCityState
15330 Eighty FourPA
15510SomersetPA
15201PittsburghPA
15202 PittsburghPA
15203 Pittsburgh PA
15204Pittsburgh PA
15205 PittsburghPA
15206Pittsburgh PA
15207Pittsburgh PA
15208Pittsburgh PA
15209 Pittsburgh PA
15210Pittsburgh PA

  因爲Pittsburgh、Eighty Fou和Somerset、PA都不依賴於理賠,而依賴於與信息相關的Zip代碼,它不是直接歸屬於支付表的。儘管這並不是此表的唯一問題,但是它消除了與城市、州、Zip代碼依賴所引發的困難。

Claim_numClaimant_nameClaimant_address Claimant_zip
123456789Jennifer Smith 1234 Main 15201
234567890Bill Smith7852 Eagle15202
147258369 John Jones 4562 Edge15330
258369147 Eleanor Stillwater7531 West Eastern 15510

  其它的能夠遷移到其它表從而使理賠表符合第二範式的信息包括賠償金編號和賠償金描述組合,只需要把賠償金編號存儲在理賠表中。採用這種方法時,任何對於給定編號而對描述進行的更新需要做一些改變,它可以改變賠償金錶中的某行的某列,而且這不會發生更新異常,但是如果你更新某個影響成百上千個實體的表的某一列就可能發生更新異常了。相同的邏輯可以應用在調解人和代理人上,把他們的信息遷移到自己的表中,只需要在理賠表中存儲編號列的值,這樣就容易通過連接訪問輔助信息了。

award_cdaward_desc

adjuster_cdadjuster_name

agent_cd agent_name

  第三範式(3NF)

  第三範式規則查找以消除沒有直接依賴於第一範式和第二範式形成的表的主鍵的屬性。我們爲沒有與表的主鍵關聯的所有信息建立了一張新表。每張新表保存了來自源表的信息和它們所依賴的主鍵。

  注意:通常把第三範式說成是"鍵,全都是鍵,除了鍵之外沒有任何信息"。

CLAIM_Num、CLAIM_STATUS 、ACCIDENT_DT、REPORTED_DT、 ENTERED_DT、 CLOSED_DT 、 DEATH_DT、 ASSIGNED_DT、 ADJSTER_CD、 AGENT_CD、AWARD_CD、 LOCATION、SITE 、 DEDUCTIBLE_RECOVER、 DEDUCTIBLE_REMAIN 、 POLICY_NO 、 STATE、 RUN_DT、 ACTIVITY_DT、 ENTRY_DT、 REOPEN_DT、 INSURED_NAME、 INSURED_ADDRESS、 INSURED_PHONE、 INSURED_ZIP、 CLAIMANT_NAME、 CLAIMANT_ADDRESS、 CLAIMANT_ZIP

圖4:第三範式的理賠表

  在第三範式中可以看到理賠表的更多的變化,在該表中被保險人姓名、地址、電話號碼、Zip代碼更加依賴於簽訂的策略而不是理賠本身。因此,我們能把被保險人的信息放入策略表中。這使得理賠表的剩餘信息與理賠更加直接相關,把其它所有信息放入自己的表中而保證了足夠(沒有遺漏)信息。這些表的一個簡單的連接能夠重新構造源表的信息,這也是關係代數和關係運算(關係理論和關係數據庫依賴的基礎)的目標。

POLICY_NOINSURED_NAMEINSURED_ADDRESS INSURED_PHONEINSURED_ZIP

  第三範式通常是人們能夠得到的規範化的最高等級,它一般也是實踐中規範化和標準化數據的最高層次。但是還有更多的範式。層次越高,採用簡單的步驟完成的困難就越大,而它就越來越靠近理論了。

  規範化或者沒有規範化--以及你可以採用的規範化擴展--通常是相關人員綜合的結果。如果有足夠的重要的需求,把某片信息存儲在某個位置,而它不一定嚴格符合某種範式的定義,這種存儲也是應該被尊重的。另外,規範化的結果需要以表和數據庫的使用爲基礎。通常,在決策支持系統或數據倉庫中,由於數據倉庫的時間變量組件的映象,我們會強烈渴望得到極端的沒有規範化的信息(特別是在事實表中)。

  在面向團隊的環境中,這些決定都是部門的決定(或者是共同的指導決定)。希望這些指導方針能夠幫助你瞭解規範化,幫助你作出更有見識的決定。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章