一. 關(guān)于數(shù)據(jù)冗余與異常
數(shù)據(jù)庫的規(guī)范化
數(shù)據(jù)庫規(guī)范化是一種在數(shù)據(jù)庫中組織數(shù)據(jù)的技術(shù)。 規(guī)范化是消除冗余(重復(fù))和不良特性(如插入異常,更新異常和刪除異常)的方法。 這是一個多步驟的過程,將數(shù)據(jù)放入表中,再從關(guān)系表中刪除重復(fù)的數(shù)據(jù)。
規(guī)范化主要用于兩個目的:
- 消除冗余(無用)數(shù)據(jù)。
- 確保數(shù)據(jù)依賴性是有意義的,即數(shù)據(jù)是有邏輯性地進行存儲的。

數(shù)據(jù)冗余直觀上可以說就是一張表里不同位置有大量重復(fù)的數(shù)據(jù),這種冗余不僅僅增加了存儲量,也使得我們會更容易遇到三種異常(插入異常,更新異常和刪除異常)。
為了更好的理解這三種異常,我們可以看一下下面這個樣例。
| 學(xué)號 | 姓名 | 院系 | 教授 | 教授電話 |
|---|---|---|---|---|
| 401 | Akon | CSE | Mr. X | 53337 |
| 402 | Bkon | CSE | Mr. X | 53337 |
| 403 | Ckon | CSE | Mr. X | 53337 |
| 404 | Dkon | CSE | Mr. X | 53337 |
在上表中,我們有4名計算機科學(xué)的學(xué)生數(shù)據(jù)。 他們的院系信息,教授和教授電話記錄都是重復(fù)的,這就是數(shù)據(jù)冗余。
插入異常
假設(shè)有一個新的學(xué)生入學(xué),除非他選擇了一個院系,否則學(xué)生的數(shù)據(jù)不能被正確插入,因為我們將不得不將院系信息設(shè)置為NULL。
此外,如果我們需要再插入同一院系的100名其他學(xué)生的數(shù)據(jù),那么所有這100名學(xué)生的院系信息都會被重復(fù)記錄。
更新異常
如果X先生離開大學(xué)怎么辦? 或者不再是計算機科學(xué)系的教授了怎么辦? 在這種情況下,所有的學(xué)生記錄都必須要更新,如果不小心遺漏了任何一條記錄,都會導(dǎo)致數(shù)據(jù)不一致的出現(xiàn)。
刪除異常
在我們的學(xué)生表中,學(xué)生信息和學(xué)院信息這兩種不同的信息被保存在了一起, 因此在學(xué)年結(jié)束時,如果所有學(xué)生記錄都被刪除,我們同時也就失去學(xué)院信息。
二. 范式(Normal Form)
范式是“符合某一種級別的關(guān)系模式的集合,表示一個關(guān)系內(nèi)部各屬性之間的聯(lián)系的合理化程度”。
很晦澀吧?實際上你可以把它粗略地理解為一張數(shù)據(jù)表的表結(jié)構(gòu)所符合的某種設(shè)計標(biāo)準(zhǔn)的級別。就像家里裝修買建材,最環(huán)保的是E0級,其次是E1級,還有E2級等等。數(shù)據(jù)庫范式也分為1NF,2NF,3NF,BCNF,4NF,5NF。一般在我們設(shè)計關(guān)系型數(shù)據(jù)庫的時候,最多考慮到BCNF就夠。符合高一級范式的設(shè)計,必定符合低一級范式,例如符合2NF的關(guān)系模式,必定符合1NF。作者:劉慰
鏈接:https://www.zhihu.com/question/24696366/answer/29189700
來源:知乎
第一范式(1 NF)
要使表格處于第一范式,應(yīng)遵循以下4條規(guī)則:
- 它屬性/列 都是不可再分的。
- 存儲在任意同一列中的值都屬于相同的域
- 表中的所有列應(yīng)具有唯一的名稱。
- 數(shù)據(jù)存儲的順序并不重要
這其中最關(guān)鍵的規(guī)則是第一條:屬性不可再分
舉例,如下表這樣401和492學(xué)生選了多于兩門課,對于他們倆的"課程"屬性是可以再分的,所以這樣的表是不符合1NF的。
| 學(xué)號 | 姓名 | 院系 | 課程 |
|---|---|---|---|
| 401 | Akon | CSE | c1,c2 |
| 402 | Bkon | CSE | c1,c2 |
| 403 | Ckon | CSE | c1 |
| 404 | Dkon | CSE | c2 |
可以改為
| 學(xué)號 | 姓名 | 院系 | 課程 |
|---|---|---|---|
| 401 | Akon | CSE | c1 |
| 402 | Bkon | CSE | c1 |
| 401 | Akon | CSE | c2 |
| 402 | Bkon | CSE | c2 |
| 403 | Ckon | CSE | c1 |
| 404 | Dkon | CSE | c2 |
但是,就算是這樣符合1NF的表仍然會有很多,因為1NF其實是最為基本的要求,不滿足1NF的數(shù)據(jù)庫甚至不一定能建立成功。
比如,上面提到的三個異常
- 插入異常。如果學(xué)校建了新系,但還沒有招生,這個系就不能被插入數(shù)據(jù)表里
- 更新異常。如果Akon轉(zhuǎn)系了,那在上表中需要更改兩行院系&課程記錄
- 刪除異常。如果所有學(xué)生記錄被刪除,院系記錄和課程也就不復(fù)存在了
第二范式(2NF)
要使表格處于第二范式,
它應(yīng)該在滿足第一范式的前提下,沒有部分函數(shù)依賴。
首先我們來了解下什么是依賴。
對于一個表來說,如果通過其中一個屬性可以找到唯一對應(yīng)的一條記錄,那么我們可以說它為本表的主鍵(Primary Key)。
比如下表中,每個學(xué)生的學(xué)號是存在且唯一的,但是名字可能會有重名存在,學(xué)號為主鍵(Primary Key),而姓名就不是。
同時,我可以通過【學(xué)號】查到任何一行的任何一列屬性,比如通過【學(xué)號】查【院系】,通過【學(xué)號】查【課程】,通過【學(xué)號】查【姓名】。這時我們可以說,其他的這三個屬性依賴于學(xué)號。
| 學(xué)號 | 姓名 | 院系 | 課程 |
|---|
那什么是部分依賴呢?
候選鍵(Candidate Key)就是,當(dāng)兩個屬性結(jié)合在一起可以唯一確定任何一條記錄的情況。比如在一張學(xué)生成績表中
| 學(xué)號 | 姓名 | 課程號 | 分?jǐn)?shù) | 教師 |
|---|---|---|---|---|
| 001 | A | L1 | 90 | Mr.X |
| 001 | A | L2 | 80 | Mr.Y |
| 002 | B | L2 | 910 | Mr.Y |
【學(xué)號+課程號】 一起可以確定任何一條分?jǐn)?shù)或是學(xué)號或是教師,所以 【學(xué)號+課程號】 就是本表的候選鍵。
一張表可以有多個鍵(key),一般我們會選擇其中一個作為主鍵。
這個時候我們可以看到,教師這一屬性其實只由課程號決定,而課程號只是 候選鍵 的一部分,因此這時我們就說,教師屬性存在部分函數(shù)依賴。
那么我們要怎樣移除部分函數(shù)依賴呢。
答案是拆表。
拆表的步驟如下
- 先找出所有的非主屬性(不是主鍵也不是候選鍵包含部分的屬性),在這個例子里,鍵為【學(xué)號+課程號】,那么他倆為主屬性,剩下的都是非主屬性
- 檢查這些非主屬性是否存在部分函數(shù)依賴?!拘彰恐灰蕾囉凇緦W(xué)號】,存在;【分?jǐn)?shù)】非得要【學(xué)號+課程號】一起才能確定,不存在;【教師】只依賴于【課程】號,存在
將這些存在部分函數(shù)依賴的屬性分出去建立滿足2NF的新表,切分方法并不唯一,
在這里可以這么分
分?jǐn)?shù)表去掉 【姓名】 和 【教師】 屬性:
| 學(xué)號 | 課程號 | 分?jǐn)?shù) |
|---|---|---|
| 001 | L1 | 90 |
| 001 | L2 | 80 |
| 002 | L2 | 910 |
為 姓名 建立學(xué)生表:
| 學(xué)號 | 姓名 |
|---|---|
| 001 | A |
| 002 | B |
為 教師 建立 課程表:
| 課程號 | 教師 | 院系 |
|---|---|---|
| L1 | Mr.X | CS |
| L2 | Mr.Y | EE |
| L3 | Mr.Y | EE |
這個時候我們再回頭檢查一下上面提到的三種異常。
- 插入異常。招新生的話,學(xué)生信息可以單獨插入,有改進。
- 更新異常。如果L1號課換老師了,只用修改一次,有改進。
- 刪除異常。如果刪除所有的學(xué)生信息,教師信息還在,分?jǐn)?shù)信息也還在;但是如果我從教師表里刪掉課程L1的記錄,教師Mr.x以及CS院系信息就不復(fù)存在了,這是個大問題。
- 數(shù)據(jù)冗余變少了么?少了。
我們會發(fā)現(xiàn)仍然有些問題存在,尤其是刪除異常。
這時我們就要提到第三范式了
第三范式(3NF)
第三范式在2NF的基礎(chǔ)上,要求不存在任何傳遞依賴(Transitive dependency)。
什么是傳遞依賴?以及傳遞依賴的存在會造成哪些問題?
比如上面一節(jié)提到,如果刪除教師表里課程L1的信息,教師Mr.x以及CS院系信息就不復(fù)存在了,同時,如果一名新來的教師還沒有被分配到任何課,他就不能被加入到教師表里。
這是因為,在教師表里:
1.課程號可以決定教師. A → B
2.教師不能決定課程號,因為一個教師可以教多門課. B not→ A
3.教師決定院系,因為一個教師只能屬于一個院系. B → C
這時我們就發(fā)現(xiàn),非主屬性 【院系】,也依賴于另一個非主屬性 【教師】,這種情況就叫做傳遞依賴。
而3NF的條件,就是要去除這種傳遞依賴。
解決方法有多種,這里可以將院系信息分表。
課程表只有課程號和教師信息:
| 課程號 | 教師 |
|---|---|
| L1 | Mr.X |
| L2 | Mr.Y |
| L3 | Mr.Y |
而教師表 只有教師和院系信息:
| 教師 | 院系 |
|---|---|
| Mr.X | CS |
| Mr.Y | EE |
這樣我們再檢查上面的問題,
刪除L1課程信息,Mr.X老師的信息仍然保存的很好,有改進。
新老師Mr.Z可以被插入教師表,哪怕他還沒有被分配任何課程。