關聯式資料庫 (Relational Database)是奠基在實體關聯模型(Entity-Relationship Model, ER Model)上的資料庫。每個資料庫內會包含兩個或是兩個以上的資料表所形成的組合。
實體 (Entity) 是一個離散物件,我們可以簡單的把它當作「名詞」來看待。而關聯則是描述兩個實體間的聯繫,也可以把它當作「動作」。
例子:
實體和關聯各自本身,都可以擁有其屬性。若以上頭的例子來看:
既然關聯式資料庫的組成是一張張的表格,若要確保每張資料表的一致性和完整性,那必須要達成以下條件:
若今天有以下兩張資料表,記錄下 A 公司旗下的眾多子公司和分類:
id | name | CategoryID |
---|---|---|
1 | ASub1 | 1 |
2 | ASub2 | 2 |
id | name |
---|---|
1 | Retail |
2 | Manufacturing |
透過 CategoryID 跟 分類列表內的 id 兩個值,便將這兩個表連結起來了。前者 CategoryID 稱為外鍵 (Foreign Key, FK);後者稱為 主鍵 (Primary Key, PK)。
正規化可以想成在存入資料到資料庫前,先除去資料中多餘的部份,以減少儲存空間的浪費,同時還可增進查找效率。
下方例子是一張尚未正規化前的個人資料表:
name | city | |
---|---|---|
Mike | mike@example.com | 台北 |
Andy | andy@gmail.com | 桃圓 |
Cindy | cindy@gmail.com | 桃圓 |
我們可以先對這表單進行 1st 正規化 變成以下:
id | name | city | |
---|---|---|---|
1 | Mike | mike@example.com | 台北 |
2 | Andy | andy@gmail.com | 桃圓 |
3 | Cindy | cindy@gmail.com | 桃圓 |
上圖的個人資料表中加入了主鍵 id,同時每一個欄位也僅一筆內容。若有不相關的內容,應該要改放到其他的資料表中存放。但這樣的個人資料表,若我要新增或更改城市名稱時,便會造成困擾。例:使用者現在發現他把「桃園」誤植為「桃圓」,若要修改得一筆筆改動,隨著資料量增加,出錯機會也會隨之上升。
因此,將城市名稱另外建立一個表單,並建立關聯,最後形成許多組一對多的關係,完成 2nd 正規化。
id | name | CityID | |
---|---|---|---|
1 | Mike | mike@example.com | 1 |
2 | Andy | andy@gmail.com | 2 |
3 | Cindy | cindy@gmail.com | 2 |
id | name |
---|---|
1 | 台北 |
2 | 桃園 |
如果資料表比較單純,那做到這個階段就可以結束了。不過當你發現在做完 2nd 正規化 後,在一個表單中仍有發現相依的情況,那就還可以再進行3rd 正規化。
如以下做完 2nd 的正規化訂單資料表:
id | CustomerID | customerName | staffName | StaffID |
---|---|---|---|---|
1 | 1 | Tommy | Ken | 1 |
2 | 2 | Jennifer | Hans | 2 |
3 | 3 | Jacky | Hans | 2 |
如上表,顧客 ID 、顧客名字、職員名字和職員 ID 這四個欄位整體跟訂單編號有關,但單看「顧客 ID 、顧客名字」和「職員名字和職員 ID」這兩組,其實都可以分拆出去。
所以 3rd 正規化 後會變成三張資料表:
id | name |
---|---|
1 | Ken |
2 | Hans |
id | name |
---|---|
1 | Tommy |
2 | Jennifer |
3 | Jacky |
id | CustomerID | StaffID |
---|---|---|
1 | 1 | 1 |
2 | 2 | 2 |
3 | 3 | 2 |
換個角度思考:過多層的正規化,在取用資料時,使用者就得多利用幾次或是幾層的 JOIN (關聯)指令,才能取得完整資料。如此一來,這樣較為複雜的查詢指令,會不會產生讓使用者得以察覺的效能降低?查遍網路上大眾的說法,普遍認為至少做到三層的正規化是基本的。
正規化資料表後,下一個要思考的問題是你的資料表的關聯類型,可分為 一對一、一對多、多對多三種,就留待明天的篇幅再行簡介了。