動態網站中資料庫設計優劣直接決定查詢效能與程式擴展性。無論 MySQL 或 Oracle,透過正規化消除冗餘與不協調相依,能讓 PHP 程式碼更具可讀性、易擴展、提升應用效能。
情境:建立用戶資訊表,儲存姓名、公司、公司地址、個人收藏 URL。
users
name | company | company_address | url1 | url2
Joe | ABC | 1 Work Lane | abc.com | xyz.com
Jill | XYZ | 1 Job Street | abc.com | xyz.com
問題:URL 欄位固定,需第三個 URL 時必須加欄位,擴展性極差。
users
userId | name | company | company_address | url
1 | Joe | ABC | 1 Work Lane | abc.com
1 | Joe | ABC | 1 Work Lane | xyz.com
2 | Jill | XYZ | 1 Job Street | abc.com
2 | Jill | XYZ | 1 Job Street | xyz.com
解決 URL 限制,但插入記錄時重複公司與用戶資料,資料庫膨脹且易出錯。
users urls
userId | name | compId urlId | relUserId | url
1 | Joe | 1 1 | 1 | abc.com
2 | Jill | 2 2 | 1 | xyz.com
3 | 2 | abc.com
4 | 2 | xyz.com
companies
compId | company | company_address
1 | ABC | 1 Work Lane
2 | XYZ | 1 Job Street
users 主鍵 userId 與 urls 外鍵 relUserId 關聯。但為 ABC 公司加 200 員工仍需重複公司資料。
公司名、地址與 UserId 無關,應獨立建表:
users companies urls
userId|name|compId compId|company|address urlId|relUserId|url
1 |Joe |1 1 |ABC |1 Work Ln 1 |1 |abc.com
2 |Jill|2 2 |XYZ |1 Job St 2 |1 |xyz.com
3 |2 |abc.com
4 |2 |xyz.com
公司表主鍵 compId 與 users 外鍵 relCompId 關聯。加 200 員工僅增 users 記錄,companies 單一記錄。大多數開發者認為 3NF 足夠。
發現 URL 欄位仍有冗餘(兩用戶收藏相同網址)。若 URL 由下拉選單選擇,冗餘明顯。需引入多對多關係:
users companies urls url_relations
userId|name|compId compId|company|address urlId|url relationId|relatedUrlId|relatedUserId
1 |Joe |1 1 |ABC |1 Work Ln 1 |abc.com 1 |1 |1
2 |Jill|2 2 |XYZ |1 Job St 2 |xyz.com 2 |1 |2
3 |2 |1
4 |2 |2
建立中介表 url_relations,欄位皆為主鍵或外鍵,消除 urls 重複項目。查詢 Joe 的 URLs:
SELECT name, url FROM users, urls, url_relations
WHERE url_relations.relatedUserId = 1
AND users.userId = 1
AND urls.urlId = url_relations.relatedUrlId;
原則:原表格必須可由分離出的表格重新建構。確保無多餘欄位,結構與實際需求一致。極大型資料才需應用,一般專案較少用到。
「物極必反」,過度正規化導致關聯複雜、查詢效能下降。實際應用應依專案規模權衡,必要時測試驗證,設計最合理結構。正規化規範源自 1972 年 Codd 博士論文及後續關係數學理論化。