有問題的時候,我經常回來部落格園尋找答案,久而久之,總結了一些東西。
妄自菲薄,請大家多指出錯誤,並給出意見
資料庫設計三範式基本原則
第一範式:資料庫表中的欄位都是單一屬性的,不可再分。這個單一屬性由基本類型構成,包括整型、實數、字元型、邏輯型、日期型等。
也就是說,絕對不要出現下面的情況
這個很容易做到吧,呵呵。
第二範式:資料庫表中不存在非關鍵字段對任一候選關鍵字段的部分函數依賴(部分函數依賴指的是存在組合關鍵字中的某些欄位決定非關鍵字段的情況),也即所有非關鍵字段都完全依賴於任意一組候選關鍵字。
也就是說,絕對不要出現下面的情況
學號 |
姓名 |
年齡 |
課程名稱 |
成績 |
學分 |
97001 |
張三 |
13 |
化學 |
88 |
2 |
其中學號和課程名稱是聯合主鍵
因為:
(課程名稱) → (學分)
(學號) → (姓名, 年齡)
第三範式:在第二範式的基礎上,資料表中如果不存在非關鍵字段對任一候選關鍵字段的傳遞函數依賴則符合第三範式。所謂傳遞函數依賴,指的是如果存在"A → B → C"的決定關係,則C傳遞函數依賴於A。因此,滿足第三範式的資料庫表應該不存在如下依賴關係:
關鍵字段 → 非關鍵字段x → 非關鍵字段y
也就是說,絕對不要出現下面的情況
學號 |
姓名 |
年齡 |
所在學院 |
學院地點 |
學院電話 |
97001 |
張三 |
13 |
清華 |
中關村 |
8888888 |
因為:(學號) → (所在學院) → (學院地點, 學院電話)
特別注意:有時為了提高效率,第三範式可以被打破!多見於外鍵特別多而且資料量巨大的表。為了提高查詢的效率,可以犧牲增刪改的效率。
關於表、視圖、預存程序:
表就是用來儲存資料的,要盡量滿足三個範式,不要出現冗餘的東西。
視圖是用來查詢資料的,對於沒有外鍵的基礎資料表,可以直接用來查詢。對於外鍵比較多的業務表,查詢操作全部要通過視圖。
預存程序和觸發器我基本不用,我傾向於在資料庫層面不要體現太多的業務(甚至不體現),我把業務全部集中在代碼層面。其實還有另外一個原因,我不太精通這方面的技術,見諒見諒。
關於索引:
有朋友舉過很好的一個例子,彙總索引就像拼音檢索,非彙總索引就像部首索引。
拼音索引在整個字典中都是排好序的,就像查英文單詞,你只要按照每頁角上的英文索引就可以向後翻或者向前翻來找到你想要的單詞。但是想象一下,如果造出了一個新單詞,再插入字典中,那將是很恐怖的事情,整個該新單詞後面的全部單詞全都要向後挪,等於字典重新做了。所以,彙總索引對於尋找、排序、篩選(比如,我就想看A到C的所有單詞)是很方便的事情。
但是,就算有彙總索引,有的SQL關鍵字也還是要導致全表掃描的,比如說,我要找類似於*ng的單詞(LIKE '%ng'),你就要找遍整個字典(全表掃描),但是如果你找類似於ac*的單詞(LIKE 'ac%')就很容易。
非彙總索引就是一對一個關係了(非彙總索引就是對應每條內容的地址),你找某一條記錄一下就可以定位到。大家可以想想什麼樣的欄位可以作為非彙總索引,沒錯,一個就是類似於單據號的欄位,每條記錄都不一樣,而且幾乎每次都只找一條。還有什嗎?對,外鍵,外鍵都要加非彙總索引,我實際測過,一個表有很多外鍵,視圖中都是用Inner Join串連起來的,相比之下,10萬條資料,沒有建立非彙總外鍵索引的情況下,試圖開啟用12秒,為每個外鍵建立非彙總索引,開啟速度馬上縮短到6秒。
我引用聯機文檔中的原話來描述一下:
在建立非叢集索引之前,應先瞭解訪問資料的方式。考慮對具有以下屬性的查詢使用非叢集索引:
- 使用 JOIN 或 GROUP BY 子句。
應為聯結和分組操作中所涉及的列建立多個非叢集索引,為任何外鍵列建立一個叢集索引。
- 不返回大型結果集的查詢。
- 包含經常包含在查詢的搜尋條件(例如返回完全符合的 WHERE 子句)中的列。
關於主鍵:
我比較傾向於主鍵的業務無關性,用的是著名的GUID。雖然佔用空間較大,效率也偏低,但是在找不出其它更好的方法。
需要注意的是,建立主鍵時,SQL Server預設會把主鍵設定為彙總索引,一定要把他去掉,設定在更有意義的其它欄位上,或者壓根就不設。
GUID的好處很多,有:
產生主鍵簡單,可預知。
沒有並發時主鍵重複的煩惱。
防止使用者手動更改資料庫中的資料,一看到GUID,就都嚇回去了。
避免資料庫表遷移時的麻煩(用自增型的主鍵,在表遷移時簡直就是災難)。
避免了基礎資料表更新時外鍵的串聯更新(主要體現在主鍵業務無關性上)。
歡迎大家多提意見。