網上搜的範式說明大部分都看不懂的..
轉一篇很好的文章"細說數據庫範式"http://www.cnblogs.com/KissKnife/
"(開頭的幾句話很精闢)
理論性的東西,往往容易把人人都看得懂的東西寫成連鬼都看不懂,近似於主任醫生開的藥方。從前學範式的時候,把書中得概念翻來覆去看,看得痛心疾首深惡痛絕,再加上老師深切誤導,最後一塌糊塗。藉助網絡資源,自己寫了一篇,自己是看懂了,希望對大家也有所幫助,有錯誤幫忙指正。
數據庫範式(Normal forms):是用於規範關係型數據庫設計,以減少謬誤發生的一種準則。
1NF(first normal form):
Table faithfully represents a relation and has no repeating groups.
數據庫表必須如實地展現“關係”,並且不允許有“重複組”出現。
這樣的概念真是令人痛心疾首,我們只好再搬出1NF的的作者之一Chris Date的解釋:
1. There's no top-to-bottom ordering to the rows.
(任意兩行沒有特定的順序關係。不存在一個特定的理由要某一行必須在另一行之前。)
2. There's no left-to-right ordering to the columns.
(任意兩列沒有特定的順序關係。)
3. There are no duplicate rows.
(不允許存在重複的行。如果一張表沒有Unique Key,事實上它是違反1NF的。)
4. Every row-and-column intersection contains exactly one value from the applicable domain (and nothing else).
(不允許出現空值Null,這一點不同作者是有爭議的。事實上我們常常違背這點。)
5. All columns are regular [i.e. rows have no hidden components such as row IDs, object IDs, or hidden timestamps].
(不允許存在隱藏字段。不知道Oracle的Rowid屬不屬於這個?)
有人從第四點的“one value”大肆挖掘,於是我們就見到了書上這樣的定義:“如果一個關係模式R的所有屬性都是原子的,即不可再分的基本數據項,則RÎ1NF”。
這一點被認爲是1NF的核心,“關係模式R”↔“表”,“屬性” ↔ “列”,下面是一種與1NF不一致的情況,通常這是一類很明顯的設計缺陷:
ID |
Artist |
FavoriteColor |
…… |
1 |
Babyface |
Blue,Yellow |
…… |
2 |
Sting |
Green |
…… |
對上例我們不能把它拆分成FavoriteColor1、FavoriteColor2……因爲首先我們不能確定該拆分成幾列;其次FavoriteColor1與FavoriteColor2在結構、含意方面都是相同的,這實際上也是一類“repeating group”;同時這種設計會導致某些查詢困難,比如“有哪些藝人喜歡黃色?”
解決方案是將表拆分成兩個:
ID |
Artist |
…… |
1 |
Babyface |
…… |
2 |
Sting |
…… |
ID |
FavoriteColor |
1 |
Blue |
1 |
Yellow |
2 |
Green |
總結:
對1NF最核心的 “原子性”,違反此規範的可能性:接近於0%。不過,網上很多帖子說在關係型數據庫中根本不可能違背1NF,我認爲這是不對的。
2NF(second normal form):
No non-prime attribute in the table is functionally dependent on a part (proper subset) of a candidate key.
不存在非主屬性對任一候選鍵的部分函數依賴。
如果解釋完下面幾個概念,這個定義就可以讀懂了:
Superkey:超級鍵(L),如果屬性或屬性組合能唯一標識一條記錄,則它是一個Superkey。
Candidate key:候選鍵,當Superkey只包含一個屬性時,則它是一個候選鍵;當Superkey包含一組屬性時,僅當這一組屬性不包含另一Superkey時,它是一個候選鍵。換句話說,候選鍵是“純淨的”、最小化的Superkey。
Non-prime attribute:非主屬性,未在任何候選鍵中出現的屬性,即爲非主屬性。
舉例來說,對錶{First_name,Last_name,Address},假定全名不重複,則:
Superkey:
{First_name,Last_name}
{First_name,Last_name,Address}
Candidate key:
{First_name,Last_name}
Non-prime attribute:
Address
淺白版:“2NF針對的是複合候選鍵(即鍵包含的字段個數>1)的情況,非主屬性不能只依賴於複合候選鍵中的一部分字段。”顯然,如果是非複合候選鍵,如果它符合1NF,那麼它一定符合2NF。
假設有這樣一張涉及藝人與唱片公司的關係表:
Artist 藝人 |
Company 唱片公司 |
DurationYears 簽約總年數 |
CompAddr 公司住址 |
Babyface |
Solar |
4 |
Indiana |
Babyface |
Laface |
2 |
Indiana |
顯然,{Artist,Company}爲可以作爲一個候選鍵,DurationYears在這沒有問題,但CompAddr是違反2NF的,它只依賴於候選鍵的一部分(依賴於Company),這是違反2NF的,爲了消除這種情況,我們可以:
Artist 藝人 |
CompID 唱片公司 |
DurationYears 簽約總年數 |
Babyface |
1 |
4 |
Babyface |
2 |
2 |
ID |
Company 唱片公司 |
CompAddr 公司住址 |
1 |
Solar |
Indiana |
2 |
Laface |
Indiana |
總結:
對於2NF,如果關係中的候選鍵只包含一個屬性,可以直接略過。
在考慮2NF的過程中,不要把幾個無關的實體的屬性雜揉放在一個關係中,比如Artist是一個實體、Company是一個實體,它們可以有一系列的關聯表(也是實體),但在關聯表中儘量不要引入前兩個實體的無關屬性。
3NF(Third normal form)
Every non-prime attribute is non-transitively dependent on every key of the table.
不存在非主屬性對任一鍵(候選鍵)的傳遞依賴。
傳遞依賴,你可以顧名思義,這裏就不再引入定義了,舉個例子,有下面一張表:
Tournament 賽事 |
Year 年份 |
Winner 冠軍 |
Winner Date of Birth 冠軍生日 |
Indiana Invitational |
1998 |
Al Fredrickson |
21 July 1975 |
Cleveland Open |
1999 |
Bob Albertson |
28 September 1968 |
Des Moines Masters |
1999 |
Al Fredrickson |
21 July 1975 |
Indiana Invitational |
1999 |
Chip Masterson |
14 March 1977 |
這裏的候選鍵爲{Tournament,Year},顯然有這樣的決定關係:
{Tournament,Year}→Winner
{Tournament,Year}→Winner→Winner Date of Birth
其中第二條就屬於違反3NF的情況,因爲Winner Date of Birth依賴於Winner而不是直接依賴於候選鍵。這種情況下,可以將Winner,Winner Date of Birth單獨作爲一張表,這裏不贅述。
總結:
我覺得大多數人憑藉直觀感覺,就可使設計的關係符合3NF,所以這些理論,你只需要姑且讀之。
BCNF(Boyce-Codd normal form)(Boyce與Codd是該範式的兩名作者。)
Every non-trivial functional dependency in the table is a dependency on a superkey.
表中的任何非平凡函數依賴,都必須是對superkey的依賴。
non-trivial functional dependency:非平凡函數依賴,如果存在一個決定關係x→y,且y並非x的子集,則叫着y非平凡函數依賴於x。
BCNF與3NF的最大區別是它並不僅針對非主屬性(non-prime attribute)來說,它發生的時候常常是表中根本不存在非主屬性,以至於它不可能違反2NF或3NF。而BCNF的出現就是爲了擴大“打擊面”。
於是BCNF的主旨是:補充對發生在主屬性(prime attribute)身上的函數依賴的約束,因爲對於非主屬性的約束已經在3NF中完成了。
例子,使用關係表描述學生、課程、教師的關係(假定一名教師只負責一門課程,一門課程則可以由多位教師負責):
Student 學生 |
Course 課程 |
Teacher 教師 |
S1 |
C1 |
T1 |
S1 |
C2 |
T2 |
S2 |
C1 |
T1 |
S2 |
C2 |
T3 |
S2 |
C3 |
T2 |
候選鍵:
{Student,Course}
{Student,Teacher}
因此這裏不存在非主屬性,而在主屬性的函數依賴中,存在Teacher→Course,這屬於違反BCNF的情況。
可是,問題是這個表看起來還挺正常的啊?!它的毛病在於,我們無法阻止類似最後一行這樣的數據插入,而這會導致與前提“一名教師只負責一門課程”違背。所以我們還是需要將它拆分:
Student 學生 |
Teacher 教師 |
S1 |
T1 |
S1 |
T2 |
S2 |
T1 |
S2 |
T3 |
Teacher 教師 |
Course 課程 |
T1 |
C1 |
T2 |
C2 |
T3 |
C2 |
這樣,在“Teacher-Course”表中,藉助主鍵的幫助,最後可以避免違背“一名教師只負責一門課程”這個前提。
那麼,如果沒有這樣一個前提,是初的設計是否符合BCNF?目前看來是的。
真實的情況可能更爲複雜,下面這個更接近於我的一些經歷:
1)學生需要學習多門課程
2)一門課程可能有多位教師負責
3)一位教師可能負責多門課程
4)某一班級的某一課程對應的教師是固定的(一位)
據此,爲了描述學生、課程、教師三者的關係,從這一團亂麻中最早跳出來的大概是這樣的表:
Student 學生 |
Class 班級 |
Course 課程 |
Teacher 教師 |
候選鍵:
{Student,Course}
我們可以明顯地看到Student→Class違反了2NF,於是:
Student 學生 |
Class 班級 |
Class 班級 |
Course 課程 |
Teacher 教師 |
從這兩張表,仔細考慮,即便我們通過Class關聯兩張表,還是無法得出學生與課程的關係(只能得出可供該學生選擇的課程),所以我們需要再添加一張表:
Student 學生 |
Course 課程 |
最後大概是這麼三張表,可能還有其它的方案,這裏只是舉例說明,就不糾纏了。
在BCNF之後,還有4NF,5NF,DKNF,6NF,等什麼時候有空了再看看是什麼東東。
"
再轉一篇百度文庫裏的文章, 沒有上篇那麼通俗易懂但是內容很全
"
範式
就關係數據庫而言,一貫認爲:從其他元素中消除數據冗餘問題,去除重複往往以減少冗餘, 從特定的表中最小化冗餘意味着擺脫不必要的數據。
商業上來講,主要目標是通常保存空間和組織的數據可用性和可管理性,而不犧牲性能。此外,要求強烈繁忙的應用程序和最終用戶的需要往往需要以多種方式打破規則的範式,以滿足性能要求。第三範式以外的範式常常被忽視和有時甚至是第三範式本身就是多餘的。
範式是一個升級的過程,每個上層的模式都是建立在下一級範式之上的。
消除數據冗餘的影響如下:
❑物理空間需要存儲的數據減少。
❑數據變得更有組織。
❑範式化允許修改少量的數據(即單記錄)。換言之,一個表的具體字段記錄更新時,會影響其他引用他的表。
首先我們對一些概念性的東西來進行一個總結,通過對這些概念的理解,從來從根本上做到合理的數據庫設計:
異常
添加異常:當我們添加一條記錄的時候,他依賴的主表記錄還沒有記錄,而該記錄已經插入成功。
刪除異常:當我們的主表記錄刪除,而依賴他的子表沒有清空對應的記錄。
更新異常:當我們的主表記錄有更新草組,而已來他的子表沒有相應的更新記錄。依賴,決定因子
函數依賴:當Y的值由X決定的時候,我們就說Y函數依賴於X,這就類似於一個線性方程:Y=X+1;類似的ERD圖中,我們這樣表示 ,很清楚的看到表Category,中的主鍵是CategoryID,他決定着其他字段的值Name和Pic,我們就說Name或者Pic 函數依賴於CategoryID,他們之間就是一個函數依賴關係。
決定因素:如上例中,CategoryID就是一個決定因素,他決定其他字段的值,Y=X+1中,X就決定着Y的值,雖然加了一個常量。
傳遞依賴:當X決定Y,Y決定Z的時候,我們就說Z傳遞依賴於X,,從這個ERD圖中,我們看到Account帳號表中的City字段,他被AccountID所決定,而City字段的值又決定了College的值,因爲大學肯定是被城市所決定,所以College就傳遞依賴於AccountID。
候選鍵:候選鍵(潛在的或允許的主鍵)可以扮演主鍵的角色他可以是一個表中的一個字段或組合字段——也就是一條記錄中的唯一標識。,我們看到這個表,Customer表(客戶表),字段分別表示,客戶ID,客戶名,貨幣縮寫碼,貨幣,轉換匯率,地址。這個表我們沒有定義主鍵,但是我們可以推測那些可以成爲主鍵,那麼那些鍵就叫做候選鍵。,我們就看到了,所有能成爲主鍵的可能,表中的#就是主鍵的標識符。
完全函數依賴:當X決定Y,但是X不被X和Z的組合所決定,換句話說,YE依賴於獨立的X,如果Y依賴於X加上一些其他的東西,那就不是完全函數依賴,本質上,決定因素X不能是一個組合鍵。,我們來看到旅遊表Travel,Country是旅遊的國家,Populication是旅遊的城市,同時TravelID和CountryID是主鍵,可以看出來只有CountryID決定着Populcation人口,但是這裏有兩個主鍵,所以Populication並沒有完全函數依賴於主鍵組合,只部分依賴於CountryID
多值依賴:某個字段中的值之一個集合,或者是用某種分隔符分割開來的元素集合,我們就稱爲多值依賴。很經典的,Path保存的這個遞歸表的所有上司的級別,比如老大的ID是1,老2是2,Path 就保存1,2,像這樣的字段,我們就稱爲多值依賴。
循環依賴:循環依賴就如其名,是一個個閉環的依賴系統。A依賴於B,B依賴於C,C依賴於A。範式(學術定義)
第一範式(1NF):消除表中所有重複的記錄,除了主鍵以外的所有其他字段全部依賴於主鍵。
第二範式(2NF):所有非鍵值字段必須全部完全函數依賴於主鍵,當一個字段完全函數依賴於一組組合主鍵的部分函數依賴是不允許的。
第三範式(3NF):消除傳遞依賴,意味着一個字段必須非間接的依賴於主鍵 正規化範式(BCDF):所有表中的決定因素必須是一個候選鍵,如果只有一個候選鍵,那麼就和第三範式是一樣的。
第四範式(4NF):消除多值依賴。
第五範式(5NF):消除循環依賴。
我們從一個比較容易的位置來理解範式,通過上述的理解,加上實際的操作範式,讓我們對數據庫的設計有一個比較深的認識,以決定什麼情況下用範式。
第一範式(1NF):通過創建一個新表來移除重複的元素,使他們成爲一個主從關係或者是one to many的關係,類似下圖:。
第二範式(2NF):建立在1NF的基礎上,就是移除重複的值到一個新表中去,新表有唯一的主鍵,而主表有一個對新表的外鍵的引用,排除存在的部分依賴。如下圖:Bookid 是book表的主鍵,而author是author1的主鍵,在book表中建立author,主表有一個對子表的外鍵引用,而不是把author也定義爲主鍵,那樣就存在部分函數依賴,因爲bookid就已經確定了title,page,isbn等等信息。
第三範式:消除傳遞依賴,如下圖:我們把多對多的關係變化成上圖的關係。這是一種簡單的形式,下面展示一個另外一種情況:這裏的表分別是客戶(客戶名,貨幣號,貨幣,貨幣,匯率,地址),提供商(客戶名,貨幣號,貨幣,匯率,地址)。首先他們的地址決定了他們的貨幣情況,而地址又是由客戶或者提供商決定的,所以他們之間存在一個傳遞依賴關係,而且最好是把相同的存在於不同的數據移植到一個新表中去。前面我們提到了這個關係,也是一個不滿足第三範式的表,City和College以及主鍵存在傳遞關係,所以可以把College移植到一個新表中去,還有一些存在訂單的表中,有類似(qty(數量),price(單價),total(總價))的結構,qty和price決定了total,而訂單號決定了qty和,price,所以也存在一中依賴關係,我們要刪除total字段,但是不是都遵循範式的表都是好的結構,我們還是要根據實際情況,比如在一個數據倉庫的設計中,彙總字段就是必須的。
超三範式(Beyond 3NF)中的one to one關係,這個主要用戶當我們表中一些字段經常存在空值的時候,我們將存在的NULL字段移到一個新表中去,然後建立1對1的關係。
BCNF範式:BCNF劃分成多個表的表格,以確保沒有一個單一的表有更多不止一個潛在的主鍵。這是我的理解BCNF 。在我看來,是BCNF 用於商業環境是“過度設計“的。從本質上講,從數學的角度上它的漂亮,但在商業環境中它不是很酷。下面的例子是一個BCNF轉換:
第四範式:消除多值依賴,很經典的一個環境就是,我們的遞歸表問題,一個Manager有多個Employee,然後每條記錄都有一個Path老表示這種關係,所以path和EmployeeId就存在一個多對多的關係。我們就應該重新建立一個新表,用來消除Path字段,新表中就保留一個EmployeeId作爲外鍵,另外一個EmployeeId用來表示他的下屬。
第五範式:消除循環依賴,如下圖:在這個實例中Solution表中的鍵都是主鍵,他們存在這樣的關係,每兩個組合的主鍵決定另外一個主鍵。比方項目1和經理1就決定了有哪些下屬屬於項目1和經理1關係,而一個經理1和他的下屬員工又決定了他們參與了那些項目。所以他們之間其實是一個循環的依賴。
反範式:這種類型的應用在商業正常化環境將導致業績不佳,更精確的數學的必要性比商業要低的多。因此:
同樣的,對於第4範式,我們很多時候都沒有必要去消除他們裏面多值的依賴,那樣對性能來說簡直是個噩夢。所以很多情況下,我們都是用類似的處理CSDN上的,顯示自己的技術就是這樣的反範式化轉換。
在商業環境中,絕大多數超越第3範式的設計都是不切實際的。因爲應用程序在3NF級別就能變現的相當出色。我們上述的很多例子,將指向箭頭反過來就是先了反範式化。所以我們要對整體的結構有個比較深的認識,才確定我們是否範式話或者反範式化,範式化越深的東西越導致表的增多,也就意味着查詢的join開銷。
總結一下反範式化的一些準則:
分離活動和靜態的數據,數據可分爲獨立的物理表,即
活動和靜態表。那些累計的歷史數據導致我們佔據了絕大多數的空間。這是影響性能的最經常的數據,在數據倉庫設計中,我們經常將無效的靜態的數據移植到數據倉庫中,由於OLAP和數據挖掘。
在表之間複製字段,在那些不是直接有鏈接表的之間複製字段,使得我們不必每次進行查詢都要通過第3方表,越少的join操作,使得性能的大幅度提升。
在夫表中建立統計字段,這樣可以減去消耗大的聚合操作,但是實時更新會給我們帶來另外的麻煩。
分離繁重和輕鬆的字段,就像把活動和靜態的數據數據表分離一樣,這個避免持續物理掃描很少使用的數據字段,尤其是當這些字段不包含空值。這是一個潛在的合理利用4NF在分離表格分爲兩個表格,相關的一對一關係。
"
上面的文章是有圖的, 由於圖太多了就沒貼, 可以在這裏下載有圖完整版
最後附上自己記的老師的理解:
2NF: 每個非主屬性完全函數依賴於碼。(沒有非主屬性屬於2NF)
3NF: 每個非主屬性既不部分依賴於碼,也不傳遞依賴於碼。
BCNF:每個非主屬性和主屬性既不部分依賴於碼,也不傳遞依賴於碼。(徹底解決刪除異常問題)
最後的最後附一張非常簡單明瞭的圖:
網上的關於多值依賴的解釋:
"
什麼是多值依賴?書上的概念是:設R(U)是屬性集U上的一個關係模式。X,Y,Z是U的子集,並且Z=U-X-Y.關係模式R(U)中多值依賴X→→Y成立,當且僅當對R(U)的任一關係r,給定的一對(x,z)值,有一組Y的值,這組值僅僅決定於x,與z無關!太抽象了!看不懂!
"