寫在前面:本來「程式設計師應知」系列中應該寫的都是與程式設計師密切相關的內容,而資料庫設計似乎應該是資料庫管理員的工作。然而,在實際的工作環境中,我所經歷幾乎所有的專案中,資料庫設計工作都是由程式設計師來完成的;就算我們是不需要做資料庫設計的程式設計師,也至少需要對資料庫的結構有充分的理解,那樣也便於我們編寫和維護系統。思量再三,我還是將這篇與資料庫設計相關的文章放在了這個系列當中。
在幾乎所有的企業級應用程式中,包括各種mis、erp、crm等等,都會使用資料庫,這樣的好處是顯而易見的,很容易地實現了資料層和業務邏輯層的分離,而且對於效能的優化也在一定程度上提供了便利。
然而,在我所經歷過的專案中,某些資料庫的設計會存在一些問題,尤其普遍的就是下面將要描述的這兩點,個人覺得是應該避免的誤區,總結出來與大家討論。
誤區之一 備用字段
現象描述:
在資料表中,不僅設計了當前所需要的字段,而且還在其中留出幾個字段作為備用。
比方說,我設計了乙個人員表(person),其中已經新增了各種必要的字段,包括姓名(name)、性別(***)、出生年月日(birthday)等等。大功告成之後,我忽然想到,將來系統中應該還會有很多其它與人相關的內容吧,比方說畢業院校,比方說工作單位等等,儘管現在根本不需要填寫,以後可能還是會用到的吧。拍腦袋一項,那就加入5個varchar2型的字段,分別叫做text1、text2……text5,然後又想,應該還有一些日期型的字段需要備用,就又建立了三個date型的字段,分別起名叫做date1、date2、date3,……
原因分析:
大家應該已經看出問題了,在這個資料表中存在大量暫時無用的字段,我們可以稱之為備用字段,它們的作用是什麼呢?就是以防萬一,防備可能的情況。
這似乎可以叫做防患於未然,等到時候需要的時候,就不需要在表中增加新的字段了,而且這樣做的話,乙個表的資料應該會被儲存在相鄰的物理空間中,這對於效能也是有好處的。
另外的原因就是,在古老的資料庫中,如果改變資料庫的定義(包括增加字段、改變欄位的型別、刪除字段等等),那麼其中所有的資料就會丟失,所以這項工作非常麻煩,我們需要先建立臨時表,將資料備份出來,然後建立新錶,將資料匯入其中,最後再刪除原來的表。
問題所在:
這樣的做法對於專案會導致很多問題,而且原先想要解決的問題並不一定能夠解決,不信的話,請往下看。
問題一:增加大量備用字段,必定會浪費很多空間,儘管其中可能都沒有具體的資料,但是僅僅是空字段也會佔據一定的空間的。
問題二:由於命名的特點,如果沒有完善的文件管理流程,用不了多久(可能也就是兩三年),就沒有人能夠說清楚到底哪個字段代表的是什麼意義了。就算有文件管理,這些管理工作也會比較麻煩,而且在每次使用的時候都需要申請,還有可能會出現衝突的情況。
問題三:增加了這些備用欄位就真的會夠用嗎?不一定,因為我們只是每個型別的字段留出幾個備用,如果數量超過,或者要使用特殊的、不常用的型別的時候,還是需要增加新的字段。比方說在上述的person表中,我們要儲存**,那麼可能就要增加乙個blob型別的photo欄位,這在初期設計的時候可不一定會留出這樣的備用字段。而且如果沒有完善的管理,誰又能說清楚倒底哪個字段已經被使用,哪個欄位還可以使用呢?到時候還不是要增加新的字段。
解決方案:
其實上面的這種設計方式就是一種「過度設計」,我們應該做的就是「按需設計」,在經過詳細有效的分析之後,在資料表中只放置必要的字段,而不要留出大量的備用字段。
如果數量很少,而且資訊的性質與原表密切相關,那麼就可以直接在原表上增加字段,並將相關的資料更新進去。
如果數量較大,或者並非是原表物件至關重要的屬性,那麼就可以新增乙個表,然後通過鍵值連線起來。
對於表的資料的儲存位置所導致的效能問題,我們可以通過在特定時間對資料庫的資料進行重組來解決,而這項工作對於長期執行的資料庫來說,也是需要定期進行的。
誤區之二 有意義的編碼
現象描述:
使用有意義的編碼作為一條記錄的id,甚至作為資料庫的主鍵存在,例如,乙個員工的編碼設定為0203004,其中02代表員工所在分公司,03代表員工所在部門,004代表員工進入到該部門的序號。
原因分析:
id的設定方式大概有以下幾種,一種是純粹的流水號,從1開始,每次加1,或者對其將以改進,將數字轉換成為字串的格式,比方說「0000001」;一種是無意義的隨機編碼,比方說guid;還有一種就是有意義的編碼,特定的位數會代表一定的意義。
問題所在:
其實有意義的編碼會導致很多問題,請看:
問題一:對編碼資源的浪費。如果是純粹的流水號,那麼從1到10000就可以代表一萬條記錄,但是,如果使用有意義的編碼,很可能1000條記錄就會讓五位的編碼不夠用。我就遇到過真正的情況,我們公司的投保單號碼的第一位就是有意義的,代表的時該投保單所屬的渠道,後面跟著很長的一串數字(9位)。理論上來說,這些編碼永遠都不會用完,但是,最開始的三個渠道使用的是1、4、7三個編碼,但是一次新保險法的實行,導致原有的投保單作廢,於是又啟用了三個數字2、5、8,接下來公司改名,三個渠道又分別將投保單報廢,重新啟用新的開頭數字,就這樣,短短的幾年間,所有的投保單號碼全都被用完了,其實列印出來的投保單不過100萬張。
問題二:不一定是唯一的,難以作為主鍵。想一下,我們的身份證號碼就是這樣的。原先15位的時候,後三位是序號,而男性會使用奇數,女性會使用偶數,這樣就是說,乙個地區同一天生日的人,男女都不能超過500人,否則就會導致號碼的重複,儘管出現這種現象的概率比較低,但是還是客觀存在的。
問題三:代表的意義不一定準確。比方說用帶有意義的編碼來為員工定義工號,其中可能會有部門、職務等等意義,但是如果員工在部門間發生了調動,或者職級發生了改變,是否需要改變他的編碼呢?改變吧,那麼所有的歷史資料都要隨之修改一次,工作量會非常大;不改變吧,那麼代表的意義就不再準確,我們就無法從編碼中得到該員工準確的資訊。
解決方案:
所以,對於編碼,非常不建議使用有意義的編碼,要麼使用純粹的流水號,但這樣可能需要定義乙個範圍比較大的型別,對於海量記錄的資料,可能會不夠用;那樣的話就可以使用guid,這樣編碼永遠都不會重複,而且會有大量的編碼資源可用。
從上面的兩點我們可以看出,在資料庫設計的過程中,有一些在非常多系統中都使用了,但是卻帶來了很多問題的方法,對於這種情況,我們就應該仔細思考,然後痛下決心,堅決抵制。
檢視所有「程式設計師應知」系列文章。
程式設計師應知 資料庫設計的兩個誤區
寫在前面 本來 程式設計師應知 系列中應該寫的都是與程式設計師密切相關的內容,而資料庫設計似乎應該是資料庫管理員的工作。然而,在實際的工作環境中,我所經歷幾乎所有的專案中,資料庫設計工作都是由程式設計師來完成的 就算我們是不需要做資料庫設計的程式設計師,也至少需要對資料庫的結構有充分的理解,那樣也便...
程式設計師應知 資料庫設計的兩個誤區
寫在前面 本來 程式設計師應知 系列中應該寫的都是與程式設計師密切相關的內容,而資料庫設計似乎應該是資料庫管理員的工作。然而,在實際的工作環境中,我所經歷幾乎所有的專案中,資料庫設計工作都是由程式設計師來完成的 就算我們是不需要做資料庫設計的程式設計師,也至少需要對資料庫的結構有充分的理解,那樣也便...
程式設計師應知 資料庫設計的兩個誤區
寫在前面 本來 程式設計師應知 系列中應該寫的都是與程式設計師密切相關的內容,而資料庫設計似乎應該是資料庫管理員的工作。然而,在實際的工作環境中,我所經歷幾乎所有的專案中,資料庫設計工作都是由程式設計師來完成的 就算我們是不需要做資料庫設計的程式設計師,也至少需要對資料庫的結構有充分的理解,那樣也便...