爲了創建冗餘較小、結構合理的關係數據庫,設計關係數據庫時必須遵循必定的規則, 即關係數據庫的設計範式。算法
關係型數據庫的第一範式要求:數據庫
舉例來講,客戶數據表中包含客戶名和地址,地址由城市和街道組成。應用常常須要分別訪問城市或街道字段。ide
數據表customers(name,city, street)是符合第一範式的,而數據表customers(name,address)則不知足第一範式的要求。函數
定義一個知足第一範式的數據表:設計
courses(student_id, course_id, school_name, president, credit) primary key(student_id, course_id)
上表仍然存在四個問題:code
數據冗餘: school_name, president屬性重複出現orm
插入異常: 若一個新建school沒有開始招生則不能加入數據表中ci
刪除異常: 若一學院全部學生均畢業,則該學院信息消失it
修改異常: 若一學院院長更換,則需修改該學院全部學生的數據;form
若一學生轉院則需修改其所選全部課程的數據。
第二範式是在第一範式的基礎上定義的,它要求:
表的設計知足第一範式
除主鍵外全部屬性徹底函數依賴於主鍵
候選碼是函數決定全部非主屬性的最小集合,但不排除候選碼的真子集決定某些而非所有非主屬性的狀況.
而2NF禁止候選碼的真子集函數決定任何非主屬性.
如上文數據表:
courses(student_id, course_id, school_name, president, credit) primary key(student_id, course_id)
school_name和president屬性依賴於student_id
屬性,不依賴於course_id
屬性。
也就是說school,president屬性部分函數依賴於主鍵,不知足第二範式的要求。
若將上表拆分爲兩個數據表:
courses(student_id, course_id, credit) primary key(student_id, course_id) students(student_id, school_name, president) primary key(student_id)
拆分後的數據表知足了第二範式的要求。
如今分析一下,第一範式沒有解決的四個問題:
數據冗餘: 減小了school_name和president重複出現的次數
插入異常: 未解決
刪除異常: 未解決
修改異常: 解決了學生轉院的問題,未解決院長更換的問題
第三範式定義在第二範式的基礎上:
表的設計知足第二範式的要求
除非主屬性直接依賴於主鍵
看上文數據表的定義
students(student_id, school_name, president) primary key(student_id)
存在傳遞函數依賴student_id
->school_name
->president
,不知足第三範式。
進行進一步拆分:
courses(student_id, course_id, credit) primary key(student_id, course_id) students(student_id, school_name) primary key(student_id) schools(school_name, president) primary key
拆分後消除了傳遞函數依賴。
分析第三範式對上述四個問題處理。
數據冗餘: 除了主鍵外全部屬性只出現一次
刪除異常: 容許刪除全部學生而保留學院信息
插入異常: 容許創建沒有學生的學院
更新異常: 更換院長,學生轉院均只需修改一條記錄
第三範式基本上能夠解決上述問題。
BC(Boyce-Codd)範式在3NF的基礎上進一步消除了傳遞依賴.
BCNF要求:
關係模式符合3NF
函數依賴集F中全部函數依賴X->F, 左部X必須包含R的全部候選碼.
即全部候選碼都直接決定全部非主屬性.
給定關係模式R和其上的函數依賴集F, 將R進行知足BCNF的無損鏈接分解:
置初值p = {R}
檢查p中的關係模式若均知足BCNF則中止分解, 不然重複執行3.
在p中選出不知足BCNF的關係模式S, 其中必有非平凡依賴B->C, 且B不是S的候選碼.將S分解爲S1= {B,C}和S2 = R - {C}, 用S1,S2代替p中S的位置.
示例:
R = {A, B, C} F = {A->B, B->C}
候選碼A, 函數依賴B->C, 由於B不是Candidate Key因此要進行分解:
{B, C} {A, B}
4NF要求:
必須知足BCNF
非主屬性不能存在多值
示例:
phone(user_id, phone, cell)
若某用戶有多個phone同時又有多個cell時此表設計顯然不合理.
能夠採用以下的拆分方案:
phone(user_id, phone, type)
拆分後的數據表知足了4NF.