如果你的工作是軟體專案的成員,這題目一定早就會在你心裡了.市面上的軟體專案有很大的部份都需要資料庫,用來儲存企業內所需的資料,而幾乎大部份市面上的專案所需要的資料庫都是關聯式資料模型 (Relational Database),因此 database schema 的設計便是整個專案內容的設計中其中一個項目,也就是你要了解什麼是 ERM (Entity Relationship Model).也許你之前念過一些課本的內容或是上過一些課,但若沒有真正自己參與設計的話,有時你心裡一定會覺得我這樣的設計是不是好的呢?
這篇文章的內容不是要教你如何設計 database schema,其實你只要遵循著課本裡面所教你的原則來設計,設計出來的結果就不會有太意外的錯誤.比如,你知道什麼是 Entity 和 Relationship,相信你一定知道如何把 Entity 轉成資料庫中的表格以及如何用表格和欄位來實現 Relationship.我的看法是只要你正確地遵守了這些原則並且嚴格確保了正規化 (Normalization) 的存在 (一般業界的軟體專案所做的正規化至少要到 3rd normal form),設計出來的 database schema 應該都可以有八十分.以上是從資料庫的角度來看 schema 的設計,而接下來的二十分,我們就要從程式與效能的角度來思考.
在專案一開始的時候,很有可能資料庫的設計已經完成了,但是程式架構尚未完成,所以 database schema 的設計是否適當,這很難決定,畢竟存取資料的不是人,而是工程師們寫的程式,而資料存取會不會快,那就要看工程師們是怎麼寫程式了.所以你會發現,一個好的 database schema 很難在一開始就完成,除非那是個很簡單又單純的專案.
通常來說,你所設計的 database schema 能不能是個很好的設計,最大的影響是程式讀取的快慢,我們暫不考慮產品與硬體的影響,通常來說,當你的 schema 裡有很多的表格,程式在讀取資料時常常需要 join 很多的表格,這將會大大影響效能,因為 table join 雖然在關聯式資料庫中是一個很平常的事情,但也是一項成本高的運算.因此,你可以思考改進的第一個方向就是如何在不違背 ERM 和 Normalization 的原則之下將會被做 table join 的資料庫表格的數量降到最低.未來的內容,我們再來討論為何 table join 是一個成本高的運算.
第二個可以參考的方向是 Index,不論是做 table join 還是單純在一個表格上尋找資料,如果事先做好了 Index ,它將會幫助資料庫引擎能夠更快速的找到資料,因此就能更快速地完成 table join 或其他的資料存取動作.我們也會在未來的內容裡來說明 Index 如何幫上忙.
最後還有一點 De-normalization (反正規化).相信大家在課本上或實務上都會聽過這個名詞,據說它的做法能夠提升效能,但在電腦的世界裡是沒有白吃的午餐.以我個人的經驗而言,其實我不是很喜歡這東西,重點不是簡不簡單或難不難,而是它會改變了一些基本的思考而造成系統後續維護的問題. 我舉一個很簡單的例子,比如你有一個資料庫系統,裡面有一個表格,這個表格很簡單,只有兩個欄位,一個是 user id,另一個是 function id,如下所示:
User ID | Function ID |
User A | Func A |
User A | Func B |
User B | Func A |
想像這是一個很長的表格,它記錄了那些使用者可以使用那些功能.現在的情況是大部份的使用者都可以使用所有的功能,所以你可以想像使用者多功能多時,這表格有很多的筆數.你的老闆說這表格實在太長了,管理起來真麻煩,於是他想要弄一個東西,也就是如果某個使用者可以使用全部的功能的話,那麼就用 * 來代表所有的功能.
User ID | Function ID |
User A | Func A |
User A | Func B |
User B | Func A |
User C | * |
如上面表格所示,這代表 User C 可以使用所有的功能,這就是一種 De-normalization 的結果,如果你經驗不多,可能會一時覺得好像很方便,因為表格的資料筆數可以減少,同時要讀取 User C 的功能數量時也很變快,因為只有一筆資料.但你想想,你願意配合做這樣的改變嗎 ? 如果你是軟體工程師,你可能會不太高興,因為你會發現必須要寫一些 "特別" 的程式碼來處理 *.更慘的是,如果這些都是前人的工作,沒人告訴你什麼是 *,你可能要花點時間才能搞懂它的目的.
我在這裡要說的重點是並非所有的 De-normalization 都是好的,這樣的做法的確對資料庫引擎是有益的,因為資料讀取的成本變少了,但卻在程式邏輯上增加了更多的程式碼來處理.這樣一來一回的情況下很難評估是不是真的有好處.以整個系統的角度來看,除非你真的感受到很多的好處,不然就無需 De-normalization 了.