我们该如何设计数据库
上一篇 / 下一篇 2012-05-03 10:35:36 / 个人分类:数据库
b m+?5X8`'SD [0]0 对于某一种数据库设计,并不能简单的用好与不好来区分。或许真的应了那句话,没有最好,只有最适合。讨论某种数据库设计的时候,应该在某种特定的需求环境下讨论。51Testing软件测试网_s+ve8}N^8T
/AJ,f L;U}0 下面来讨论一下在项目中经常碰到的用户的联系方式储存的问题。
$B4F;q9t/[c+u:c0u2I ahT,vPt0 我在这里套用之前网络上流行“普通——文艺——二逼”的分类方式来描述我下文中提及的三种数据库设计思路,并且通过查询数据(对数据增删改,三种设计要付出的代码成本都差不多)和数据库面临需求变动两个方面来思考这三种设计各有怎样的优劣。
)c C%Z] b!A/X0%lu)Y\:I RlFQd0 普通青年:51Testing软件测试网[t!oh^.d#q
51Testing软件测试网&|3k4a.b,n,wx!n7d或许我们都这样设计过数据库51Testing软件测试网_y[i$p Z
,b$C |/G y^ M%ho0 学生表 tb_Student:51Testing软件测试网$EkH;L-L|[*~H
Name | varchar(100) | 名字 |
Telphone | varchar(200) | 联系电话 |
varchar(200) | 你懂的 | |
Fax | varchar(200) | 传真 |
这应该是最容易想到的一种思路,简单、明了。
Q0X&Zt$j#ad(qT0比如说我要查询某个人的联系方式,那么我只用一条语句就能实现:
8D9u NQeY(l.\0select Name,Telphone,Email,Fax from 表 where 条件 |
在查询的时候,这种数据库设计十分清晰,没有任何思维的难度,没有任何逻辑的挑战。但是当面临需求变动的时候,那将会是一场灾难。
$Grb2e9VK0比如现在要新增一类用户:校长。那么我们要如何处理?51Testing软件测试网W#] _?9I4T&Le,pc+Z
答案是:再加一张表 tb_Headmaster。51Testing软件测试网9swF2V_'k
事实上,再加一张表其实修改并不大,因为我们完全不需要修改学生表的存储逻辑,换句话说,这种设计是遵循了开闭原则的。51Testing软件测试网zqnCG$R
但如果学生要添加一种联系方式HomePhone的时候,灾难发生了,怎么办?
.^3NF@vk0在tb_Student中加一列HomePhone?这意味着至少要修改整个Model层(或者说DAL层),这种改动是十分巨大的,而且容易造成错误。51Testing软件测试网P0N1M6s/F6a1ax X
或者再建一张表tb_Student2,来储存HomePhone,然后以ID来关联两张表?按改动规模来说,这种改动相对简单而且不容易出错,但是在今后的维护中会增加逻辑成本。当你一而再再而三的以这样的方式来应对需求变动的时候,你的程序将变得不可理解。51Testing软件测试网*n$e B? F*H/Yq
文艺青年:
.\Q\x duv(`0UserRole | 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) | 联系信息 |
这种是一个多对多关系。当我们要查询某个用户对应的联系方式的时候,那是一场逻辑上的浩劫:51Testing软件测试网~3s8aBw"aC7FA oWk{
select ContactInfo from 表 where UserRole=某种用户类型 and OwnerID=某用户ID |
这种写法是一次性取出某个用户所有的联系方式,包括Email,HomePhone,WorkPhone等,之后我们可以在程序中判断ContactMethod的类型,将具体的联系方式加以区分。你可以简单的想到用switch-case的写法,类似这样:51Testing软件测试网B;A xBM)MY
|
R4U\Mp051Testing软件测试网r@)Koe1s.p/E-dR
|
注意,请不要试图使用类似下面这类语句来查询某用户的联系方式:51Testing软件测试网-U+c1R6[Y;f)PT u
AuC.e{\051Testing软件测试网r!JX%_!`-A2A%W
|
相信我,这种做法非常愚蠢:每当你要取出这个用户的一种联系方式,就要和数据库建立一次连接,打开/关闭一次数据库;这种做法代价是十分巨大的,即使有数据库连接池,即使有数据库缓存,都应该避免这种愚蠢的做法.51Testing软件测试网0Cs:j](n'Du