資料庫該如何設計,一直以來都是乙個仁者見仁智者見智的問題。
對於某一種資料庫設計,並不能簡單的用好與不好來區分。或許真的應了那句話,沒有最好,只有最適合。討論某種資料庫設計的時候,應該在某種特定的需求環境下討論。
下面來討論一下在專案中經常碰到的使用者的****儲存的問題。
我在這裡套用之前網路上流行「普通——文藝——二逼」的分類方式來描述我下文中提及的三種資料庫設計思路,並且通過查詢資料(對資料增刪改,三種設計要付出的**成本都差不多)和資料庫面臨需求變動兩個方面來思考這三種設計各有怎樣的優劣。
普通青年:
或許我們都這樣設計過資料庫
學生表 tb_student:
name
varchar(100)
名字telphone
varchar(200)
聯絡**
varchar(200)
***fax
varchar(200)
傳真這應該是最容易想到的一種思路,簡單、明了。
比如說我要查詢某個人的****,那麼我只用一條語句就能實現:
select在查詢的時候,這種資料庫設計十分清晰,沒有任何思維的難度,沒有任何邏輯的挑戰。但是當面臨需求變動的時候,那將會是一場災難。name,telphone,email,fax from
表 where
條件
比如現在要新增一類使用者:校長。那麼我們要如何處理?
答案是:再加一張表 tb_headmaster。
事實上,再加一張表其實修改並不大,因為我們完全不需要修改學生表的儲存邏輯,換句話說,這種設計是遵循了開閉原則的
但如果學生要新增一種****homephone的時候,災難發生了
怎麼辦?
在tb_student中加一列homephone?這意味著至少 要修改整個model層(或者說dal層),這種改動是十分巨大的,而且容易造成錯誤。
或者再建一張表tb_student2,來儲存homephone,然後以id來關聯兩張表?按改動規模來說,這種改動相對簡單而且不容易出錯,但是在今後的維護中會增加邏輯成本。當你一而再再而三的以這樣的方式來應對需求變動的時候,你的程式將變得不可理解。
文藝青年:
userrole
int對應使用者型別(none = 0, student = 1, teacher = 2, headmaster = 4)
ownerid
int對應使用者id
contactmethod
int****(none = 0, email = 1, homephone = 8, workphone = 16,mobilephone = 32,fax=64)
contactinfo
varchar(255)
聯絡資訊
這種是乙個多對多關係。當我們要查詢某個使用者對應的****的時候,那是一場邏輯上的浩劫:
select這種寫法是一次性取出某個使用者所有的****,包括email,homephone,workphone等,之後我們可以在程式中判斷contactmethod的型別,將具體的****加以區分。你可以簡單的想到用switch-case的寫法,類似這樣:contactinfo from
表 where
userrole=
某種使用者型別 and
ownerid=
某使用者id
var當然你也可以嘗試下面這種寫法,我個人認為這種寫法更優雅contact = 上面的sql語句取出來的使用者所有的****;
foreach
(var
item in
contact)
}
varcontact =上面的sql語句取出來的使用者所有的****;
txtworkphone.text
= (from
a in
contact
where
a.contactmethod ==contactmethod.work_phone
select
a.contactinfo).tostring();
//後面以此類推,***
select相信我,這種做法非常愚蠢:每當你要取出這個使用者的一種****,就要和資料庫建立一次連線,開啟/關閉一次資料庫;這種做法代價是十分巨大的,即使有資料庫連線池,即使有資料庫快取,都應該避免這種愚蠢的做法contactinfo from
表 where
userrole=
某種使用者型別 and
ownerid=
某使用者id and
contactmethod=1//
取出某使用者的email
select
contactinfo from
表 where
userrole=
某種使用者型別 and
ownerid=
某使用者id and
contactmethod=8//
取出某使用者的homephone
唔,用了那麼多的**,終於查出了某個使用者的聯絡資訊了。反正我個人覺得這種設計方式在查詢的時候,是邏輯上的浩劫。什麼?你說你很享受?好吧,看來是我腦容量不夠……
不過當我們面臨需求變動的時候,那就非常愉快了。
什麼,要加一類使用者?簡單,userrole加乙個列舉就好了。
什麼,要加一種****?contactmethod加乙個列舉就ok。
使用了這種表設計的時候,相信你會微笑著面對需求變動的
二逼青年
昨天和同事也**了下這個問題,按他的說法就是:哪個表要****,我就扔個字段進去,存json
contact
varchar(8000)
用於儲存json
舉例來說,有這麼乙個使用者:
id:1
name:張三
telphone:1234
email:123@123.com
fax:5678
那麼資料庫中就這樣存:
當我聽到這種設計思路的時候,虎軀微微一震:靠,這都行。按這種設計,我整張表都放進乙個json裡面一股腦的存進去就算了。不過震驚之後仔細想一想,其實這種設計也是有可取之處
首先,從查詢來說,和普通青年一樣,只需一句sql:
select查詢之後,就可以通過json處理函式將想要的資料取出來,在此就不贅述了contact from
表 where
條件
那麼當面臨需求變動的時候會發生什麼:
加一類使用者的時候,要新增一張表。也是符合開閉原則,原有**沒有改動
加一種****,只用存json的時候多存一點東西
不過這種設計如果要更新某條資料的話要稍微麻煩一點:先查詢一條資料,重組json之後再update
我們該如何設計資料庫
資料庫該如何設計,一直以來都是乙個仁者見仁智者見智的問題。對於某一種資料庫設計,並不能簡單的用好與不好來區分。或許真的應了那句話,沒有最好,只有最適合。討論某種資料庫設計的時候,應該在某種特定的需求環境下討論。下面來討論一下在專案中經常碰到的使用者的 儲存的問題。我在這裡套用之前網路上流行 普通 文...
我們該如何設計資料庫 三
簡單的說說吧 假設為man使用者實現的是乙個徵婚系統,而woman使用者實現的是乙個選美系統。這麼說應該能理解man和woman的不能並同一張表的原因了吧。在 我們該如何設計資料庫 二 中,園友jacklondon chen提出了一些問題,大致如下 man woman應該設計在同一張表中。使用者表大...
我們該如何設計資料庫 四
其實我一直在準備另一篇博文的基礎資料,但是和朋友聊天,他問我最近在做什麼,我說在做系統log模組,並和他交流了一下,於是這篇部落格就應運而生。其實我一直在準備另一篇博文的基礎資料,但是和朋友聊天,他問我最近在做什麼,我說在做系統log模組,並和他交流了一下,於是這篇部落格就應運而生。所有資料都可以用...