2 L# w: H' C4 c* z" [; }4 [. s2 I" W7 C ' l p5 i# t6 w- e; x : _, m/ z' r9 {- ^6 i, D $ ^& \! l5 j* [" ?: l 一个成功的管理系统,是由:[50%的业务 + 50%的软件]所组成, ( [! s6 B5 w6 }! A8 r 而 50%的成功软件又有[25%的数据库 + 25%的程序]所组成,数据库 ' n2 I+ P+ y& ?8 z 设计的好坏是一个关键。如果把企业的数据比做生命所必需的血液, " @5 T% r* h0 [7 O7 |3 V 那么数据库的设计就是应用中最重要的一部分。有关数据库设计的材- K9 @/ [, E4 D+ V: J! u& r" ], P2 M
料汗牛充栋,大学学位课程里也有专门的讲述。不过,就如我们反复 ) X) c6 T; ^: l d 强调的那样,再好的老师也比不过经验的教诲。所以我归纳历年来所( m2 U( c/ ~9 o( N n4 p% V6 }, t5 Q1 S
走的弯路及体会,并在网上找了些对数据库设计颇有造诣的专业人士' y0 P6 z9 A& S7 r) G' }1 F
给大家传授一些设计数据库的技巧和经验。精选了其中的 60 个最佳, Z4 g& Z t9 K3 o
技巧,并把这些技巧编写成了本文,为了方便索引其内容划分为 5 ; V, ~+ t7 m f7 |" a5 P- A; v 个部分:2 L% c5 [) ]/ U8 q S, S
1 K: K4 ^5 v9 m! Y 第 1 部分 - 设计数据库之前 $ W9 U1 c& C, g" |( t& p # P7 @$ s/ C' C3 T 这一部分罗列了 12 个基本技巧,包括命名规范和明确业务需求 ' Q4 s- I5 @) b, d$ h4 u: S 等。 8 v# D' T0 r. v. `$ Y% p& e 3 N8 t! _: r4 b3 ]6 N$ S; M 第 2 部分 - 设计数据库表 : r) z1 }% E1 h& L6 u/ x0 K3 L3 K1 r7 @$ X9 G- `
总共 24 个指南性技巧,涵盖表内字段设计以及应该避免的常见 - W, _1 u; a- i- i K& M4 \9 d% P 问题等。2 A, V0 c' u- L
2 ]- D, A+ j/ h' O4 R/ Y' G9 w* u; ~ 第 3 部分 - 选择键: D/ G" X4 d f; X
8 X/ ~* Z" s9 U) o+ I
怎么选择键呢?这里有 10 个技巧专门涉及系统生成的主键的正 o) o( c1 O1 w1 x; u
确用法,还有何时以及如何索引字段以获得最佳性能等。 % h* K2 G" O o: M# \& `6 C3 n0 h+ V: E' P5 T
第 4 部分 - 保证数据完整性 4 ?0 i7 {( s# m L3 j) m; H% q # i) i( b3 Q9 U 讨论如何保持数据库的清晰和健壮,如何把有害数据降低到最小 3 W+ ]) c% z4 B, } 程度。 4 X9 k, T( K# f3 c " g& i7 L3 Z% I+ I* x" ] 第 5 部分 - 各种小技巧/ H3 O4 V. d" F. W( X
2 w) L' V; h* p5 F3 r2 | 不包括在以上 4 个部分中的其他技巧,五花八门,有了它们希 7 T# \9 r a/ d: ` 望你的数据库开发工作会更轻松一些。' F: l% P; V, g7 P
4 f& `: {" k; U9 z' q; }3 b - m* h0 _" E& u
§ 第 1 部分 - 设计数据库之前 0 \% S6 G) R: s+ o! h! M3 w ──────────────. j3 Z# ~( Z7 V4 d! j) P6 ~
) @, ^ w: M- l- b- ^( I8 o6 j
■ 考察现有环境 - o1 l0 c' z) ^/ i Q) V* v- }( e$ |+ A/ T# d" |- a5 w$ A" ?5 c1 Y
在设计一个新数据库时,你不但应该仔细研究业务需求而且还要9 K6 z5 e/ b' A/ Q' Q4 s2 R$ m
考察现有的系统。大多数数据库项目都不是从头开始建立的;通常, & g5 F+ A6 i5 A, g' N 机构内总会存在用来满足特定需求的现有系统(可能没有实现自动计 6 P V4 _+ h/ H8 [% C 算)。显然,现有系统并不完美,否则你就不必再建立新系统了。1 o. l2 R8 m% @1 _
5 Y- L" c# u% I9 p' ^2 [ 但是对旧系统的研究可以让你发现一些可能会忽略的细微问题。 7 a* I0 y0 g! o3 g5 z 一般来说,考察现有系统对你绝对有好处。 & p! a: Z2 y& A: Q, R ' p2 \4 J' P9 L% ~" z% B X ■ 定义标准的对象命名规范3 P* D4 P2 k' a8 |/ ~- ~
$ ~- {5 Y3 ^$ N0 h
一定要定义数据库对象的命名规范。对数据库表来说,从项目一 2 o3 X5 \7 I& [9 D; X. C 开始就要确定表名是采用复数还是单数形式。此外还要给表的别名定5 J& C( N N2 {/ s$ a' [
义简单规则(比方说,如果表名是一个单词,别名就取单词的前 4 Y/ A7 Y$ Z$ |) E" P 个字母;如果表名是两个单词,就各取两个单词的前两个字母组成 " Y1 C+ J. J) Z; a6 Q2 Y
4 个字母长的别名;如果表的名字由 3 个单词组成,你不妨从头两) h2 a( q$ ~) \# S$ v. g
个单词中各取一个然后从最后一个单词中再取出两个字母,结果还是 ( Z4 t8 W$ a1 U1 Z+ l 组成 4 字母长的别名,其余依次类推)对工作用表来说,表名可以/ e: H& s# R4 n& b, C9 M1 b
加上前缀 WORK_ 后面附上采用该表的应用程序的名字。表内的列[ . }+ F5 ^+ T# k8 U; F4 r. f m 字段]要针对键采用一整套设计规则。比如,如果键是数字类型,你 ! R1 U+ M8 D& i 可以用 _N 作为后缀;9 d% `+ J. A) M) m% @; A) V5 ]1 w
0 p6 L6 b/ ^0 N" B1 u' Z0 \ w
如果是字符类型则可以采用 _C 后缀。对列[字段]名应该采用标 7 \1 \. ]5 _2 [' n: j/ s 准的前缀和后缀。再如,假如你的表里有好多“money”字段,你不 : k6 I: B/ s. X. ]( y 妨给每个列[字段]增加一个 _M 后缀。还有,日期列[字段]最好以 4 Z* F1 ^# D/ j! [: p: e
D_ 作为名字打头。 ) Q6 O2 I4 K9 x& ~/ B" b% s/ l f b+ s( x0 Q# q% F% z6 V1 e r
检查表名、报表名和查询名之间的命名规范。你可能会很快就被 ' V8 ?1 T r$ f# }9 C( ]$ u 这些不同的数据库要素的名称搞糊涂了。假如你坚持统一地命名这些 1 \: T4 K' s0 z# m; j# L 数据库的不同组成部分,至少你应该在这些对象名字的开头用 * g1 o) E: E) a8 N2 R& m
Table、Query 或者 Report 等前缀加以区别。 7 r g$ X! p" Z) j$ t$ ^9 V3 x \9 f8 Q6 r
如果采用了 Microsoft Access,你可以用 qry、rpt、tbl 和 , G' ]% q9 T8 }! x7 s mod 等符号来标识对象(比如 tbl_Employees)。我在和 SQL 3 Z9 e+ ]8 V$ {" O& Y) W( k
Server 打交道的时候还用过 tbl 来索引表,但我用 sp_company ! O2 y, @. B" C( g3 V3 Z. ]
(现在用 sp_feft_)标识存储过程,因为在有的时候如果我发现了/ V% _+ W s3 O& q7 a6 x/ a0 Z* V
更好的处理办法往往会保存好几个拷贝。我在实现 SQL Server ] a4 {3 Q8 K8 M I
2000 时用 udf_ (或者类似的标记)标识我编写的函数。 " ~, i: _2 z7 ~' [( v8 }. [& [: Z% w- z/ U& z/ x* f
工欲善其事, 必先利其器采用理想的数据库设计工具,比如: $ n2 t% q! R' D$ L$ Y SyBase 公司的 PowerDesign,她支持 PB、VB、Delp he 等语言,通( |& p! m& Z6 B2 ~7 l5 ~5 a
过 ODBC 可以连接市面上流行的 30 多个数据库,包括 dBase、 A, X) k* _; X$ ^! V FoxPro、V FP、SQL Server 等,今后有机会我将着重介绍 3 p+ C9 ]/ t, P PowerDesign 的使用。 ' u$ {4 }! f9 B. m- { d5 w, K+ A/ T p% ^$ I
■ 获取数据模式资源手册; Z% m; D/ |% f2 I. @
6 z+ z0 Q% _3 J% F; t* ] ]" O7 H+ Z; ` 正在寻求示例模式的人可以阅读《数据模式资源手册》一书,该 K4 w: B4 k8 D
书由 Len Silverston、W . H. Inmon 和 Kent Graziano 编写,是 5 B& H- K+ F6 C/ h7 P" a, Y 一本值得拥有的最佳数据建模图书。该书包括的章节涵盖多种数据领 " O/ Q$ R6 j( u& l" B+ i1 H 域,比如人员、机构和工作效能等。其他的你还可以参考:[1]萨师 1 J( f, \ z& W" o& C 煊王珊著数据库系统概论(第二版)高等教育出版社 1991、[2][美] 7 ^7 T1 d. D o3 W8 W( z1 w! w+ n T
Steven M.Bobrowsk i 著 Oracle 7 与客户/服务器计算技术从入门 - S+ l4 u) ?1 C# y+ ~ 到精通刘建元等译电子工业出版社, 1996、[3]周中元信息系统建模- z& `& m. \ O# I, ]. H$ @) H) | O8 b- i
方法(下) 电子与信息化 1999年第3期,1999 畅想未来,但不可忘0 P5 N, p3 z/ j6 `# `: K
了过去的教训我发现询问用户如何看待未来需求变化非常有用。这样( W6 C9 o6 c$ ?/ u. _9 @: q
做可以达到两个目的:首先,你可以清楚地了解应用设计在哪个地方 ( [+ d8 h& `7 _1 ] 应该更具灵活性以及如何避免性能瓶颈;其次,你知道发生事先没有 . Y. | m, `+ D! Q 确定的需求变更时用户将和你一样感到吃惊。" E- d w$ p/ Q! ` t) R! i
9 L2 x+ O. _/ C o" [1 x 一定要记住过去的经验教训!我们开发人员还应该通过分享自己 . Z: C1 u. a/ T! A% T 的体会和经验互相帮助。 " o6 b: X0 [2 o: j2 I' V) b+ U! e; N) Y1 s& w
即使用户认为他们再也不需要什么支持了,我们也应该对他们进. ^6 A. m' C% I2 j9 X2 l* l
行这方面的教育,我们都曾经面临过这样的时刻“当初要是这么做了8 ^ S9 n. n! \" o' l9 ^8 s
该多好..”。& W( I+ c& a; Q" @5 m& d
$ @7 G% ]8 ~' q' C* t8 L
■ 在物理实践之前进行逻辑设计6 h9 b1 D+ c; t
+ F" W) C3 }/ V' I. M3 v! w
在深入物理设计之前要先进行逻辑设计。随着大量的 CASE 工具9 w+ u" {& G. f7 [4 v4 }
不断涌现出来,你的设计也可以达到相当高的逻辑水准,你通常可以9 W) S d6 ~5 ]. r
从整体上更好地了解数据库设计所需要的方方面面。& x1 k" C* W& { V& |6 |
, \8 ~# F; q0 ?! H) y( `/ z
■ 了解你的业务3 ] k! t( V- ?* d- y1 @7 @
- F6 R6 T9 d# U0 x 在你百分百地确定系统从客户角度满足其需求之前不要在你的 ( \% M/ q5 Z7 g& E! l2 W; H- g
ER(实体关系)模式中加入哪怕一个数据表(怎么,你还没有模式?4 n* A! ^6 @( ?" ?8 O% N
那请你参看技巧 9)。了解你的企业业务可以在以后的开发阶段节约, w6 A9 u6 L8 D; r
大量的时间。一旦你明确了业务需求,你就可以自己做出许多决策了。6 u; s$ R% o+ F& H+ [' m
+ L- B c, S+ u5 ~
一旦你认为你已经明确了业务内容,你最好同客户进行一次系统 % X |: J/ U1 v3 \7 w 的交流。采用客户的术语并且向他们解释你所想到的和你所听到的。 3 `7 [6 q( u+ o. ]4 F8 r0 p 同时还应该用可能、将会和必须等词汇表达出系统的关系基数。这样 : N1 O& n! S# r6 l7 |) I, ] 你就可以让你的客户纠正你自己的理解然后做好下一步的 ER 设计。 0 ~7 e9 g9 n2 g! b' n2 @& ^; u: J' g+ [
■ 创建数据字典和 ER 图表, ^: V9 j$ d- N* f" e) G8 @
- B' E( H/ |. V' ~3 U) c1 b7 h
一定要花点时间创建 ER 图表和数据字典。其中至少应该包含每! P* E' T7 D2 s& j6 o0 x$ @, g
个字段的数据类型和在每个表内的主外键。创建 ER 图表和数据字典 ( e+ X+ r* I% a: F+ s7 Q 确实有点费时但对其他开发人员要了解整个设计却是完全必要的。越0 l/ y8 ~, h' s: i! q. ]* ?+ k- c, E
早创建越能有助于避免今后面临的可能混乱,从而可以让任何了解数* Q/ r% w; B6 _# G: g5 c6 U0 f
据库的人都明确如何从数据库中获得数据。8 c8 l4 D+ ?7 F9 S4 @- h1 {$ _
! z# V3 e, O$ u- v- H O* X 有一份诸如 ER 图表等最新文档其重要性如何强调都不过分,这 ; q' W" R2 Z* [ 对表明表之间关系很有用,而数据字典则说明了每个字段的用途以及 # v5 V8 K2 b. J 任何可能存在的别名。对 SQL 表达式的文档化来说这是完全必要的。. {$ A. ~& R0 X" B
q2 m0 b6 U, Z, N$ R1 O& q2 j ■ 创建模式5 N r9 {" c1 b O8 _
- A& e8 O$ ? [5 u# e& g4 ]
一张图表胜过千言万语:开发人员不仅要阅读和实现它,而且还; V7 r3 G) m, |9 `. Y; K5 |8 g
要用它来帮助自己和用户对话。模式有助于提高协作效能,这样在先& N. l. k9 f5 I1 ?" n
期的数据库设计中几乎不可能出现大的问题。# V/ U% L% H8 E2 { [+ f$ j$ _
( R8 Y( {. x# Y) D6 R3 q/ g 模式不必弄的很复杂;甚至可以简单到手写在一张纸上就可以了。" v" B x6 F1 A! c' @1 I
只是要保证其上的逻辑关系今后能产生效益。8 o: ~9 ?; _$ r/ ]5 x( J0 a# z0 H
- K2 b' J4 t, V( H
■ 从输入输出下手 + d' M+ y5 R6 B, ?4 U N4 k& |3 _. q( z: V3 q: n% Z
在定义数据库表和字段需求(输入)时,首先应检查现有的或者 % E5 S! ?; x: I4 i 已经设计出的报表、查询和视图(输出)以决定为了支持这些输出哪& [ @; a7 g4 _+ ?; T0 b4 N* S
些是必要的表和字段。举个简单的例子:假如客户需要一个报表按照 / G8 e: ]- ~; _/ {! ~$ k- K 邮政编码排序、分段和求和,你要保证其中包括了单独的邮政编码字 p' K- D H$ d% [" j- \0 { 段而不要把邮政编码糅进地址字段里。 4 R& R9 X, C- A' b8 x9 \2 V q; Z7 m" b
■ 报表技巧, I+ r7 l- K- [$ A9 i: D, f
. V: f' b6 U9 }" J2 `% G 要了解用户通常是如何报告数据的:批处理还是在线提交报表? : E. s) R! n. I2 F; v% _) K; E 时间间隔是每天、每周、每月、每个季度还是每年?如果需要的话还7 ^4 }4 V) l3 b0 D
可以考虑创建总结表。系统生成的主键在报表中很难管理。用户在具6 t1 |9 ^: | K2 Q; E2 ^
有系统生成主键的表内用副键进行检索往往会返回许多重复数据。 1 r( w/ p- A0 S * ]! H7 V( ~* s2 x- d1 C, _3 L) Z" R 这样的检索性能比较低而且容易引起混乱。 ; I' s7 J# O* u* V' \" r7 d( y9 t S' }' z5 r5 u. o. T% @& j4 u
■ 理解客户需求$ @& g* G. C+ Y9 c
9 c) Q" S+ F! E& L E, N) C4 w 看起来这应该是显而易见的事,但需求就是来自客户(这里要从 ; k, \1 l! `/ v a1 X 内部和外部客户的角度考虑)。不要依赖用户写下来的需求,真正的 1 o6 |/ n$ m1 P% I' P: p4 @( R4 h 需求在客户的脑袋里。你要让客户解释其需求,而且随着开发的继续,4 {; B0 n0 F% c+ }; J
还要经常询问客户保证其需求仍然在开发的目的之中。一个不变的真 . f+ _# P, a4 [9 N 理是:“只有我看见了我才知道我想要的是什么”必然会导致大量的! k# V; Q; Z" D$ V) S/ t4 w* y
返工,因为数据库没有达到客户从来没有写下来的需求标准。而更糟% T/ @ @2 v9 p. T7 T/ c
的是你对他们需求的解释只属于你自己,而且可能是完全错误的。 # M# e' o5 O4 U" e/ w 1 E. z5 a) r6 R5 E) P% ?6 s) _ ( q- U+ b# Z4 X3 W& z
§ 第 2 部分 - 设计表和字段 1 z* X1 _- \# V* j: q ────────────── # |. M% Q4 K9 T% b- r2 g0 P( o$ c. u2 s; V x
■ 检查各种变化 * `8 Y( x: {+ b- e% | f1 p+ d1 c+ ]) i! R0 E/ ?8 ~
我在设计数据库的时候会考虑到哪些数据字段将来可能会发生变& L0 P4 I2 j- A( _
更。比方说,姓氏就是如此(注意是西方人的姓氏,比如女性结婚后 ) s* X, R. Z5 w 从夫姓等)。所以,在建立系统存储客户信息时,我倾向于在单独的) I3 h2 g8 n& S6 w
一个数据表里存储姓氏字段,而且还附加起始日和终止日等字段,这 - s2 r) ?# B7 w8 X. |3 W9 R 样就可以跟踪这一数据条目的变化。 & n% G3 f2 D, U/ C# ^! q/ K/ P3 I9 g0 n! W: H2 P. @. K1 h! h
■ 采用有意义的字段名/ G% y* G3 ^3 U6 H
9 i1 M( X7 Q }! B
有一回我参加开发过一个项目,其中有从其他程序员那里继承的 5 n, |7 O( I& r0 e1 y, L 程序,那个程序员喜欢用屏幕上显示数据指示用语命名字段,这也不 ' b; D* G: B4 S1 }# l* w0 ]0 U, `$ y 赖,但不幸的是,她还喜欢用一些奇怪的命名法,其命名采用了匈牙 & V! ?- U' _ J 利命名和控制序号的组合形式,比如 cbo1、txt2、txt2_b 等等。4 r M+ H- r3 b; a! O1 b
6 T5 N' V) k: o. H' o' {$ a4 G
除非你在使用只面向你的缩写字段名的系统,否则请尽可能地把 B2 _6 R; i. ^, \' R$ ~" ]/ f 字段描述的清楚些。当然,也别做过头了,比如 , d, J3 w( k& O7 d( F7 c Customer_Shipping_Address_Street_Line_1,虽然很富有说明性, / e/ y' C7 k* ^4 y& M; C3 w/ L 但没人愿意键入这么长的名字,具体尺度就在你的把握中。; r) `. X( n) y& _$ A
/ v+ s6 a# I2 N4 ]
■ 采用前缀命名# O0 g* f0 a" E' a. L3 B) Z: Y
7 h1 e1 A/ N$ S! B
如果多个表里有好多同一类型的字段(比如 FirstName),你不 4 u* R$ k$ X! t' T/ n3 r 妨用特定表的前缀(比如 CusLastName)来帮助你标识字段。4 n4 R- y6 j5 {, C+ T7 ]# D
- n+ q1 \2 v+ i$ ^8 Q; n" n
时效性数据应包括“最近更新日期/时间”字段。时间标记对查 , U5 ~( }( i( |3 @ 找数据问题的原因、按日期重新处理/重载数据和清除旧数据特别有 3 P% I: _( s; R 用。7 L% a' g/ Z% K( `: R$ L* ~
: D: x8 ~5 f5 G7 I, O
■ 标准化和数据驱动 0 I- A! d+ \& w # C# y S' \: d 数据的标准化不仅方便了自己而且也方便了其他人。比方说,假 + {2 O1 F* {; L, Z& @0 ^ 如你的用户界面要访问外部数据源(文件、XML 文档、其他数据库等), ' D; }/ g7 s0 z 你不妨把相应的连接和路径信息存储在用户界面支持表里。还有,如 - F. a" V6 B' @( _3 L% d 果用户界面执行工作流之类的任务(发送邮件、打印信笺、修改记录 + H" X4 o& w! R 状态等),那么产生工作流的数据也可以存放在数据库里。预先安排3 h, |5 k8 @3 o: K9 R6 f1 a
总需要付出努力,但如果这些过程采用数据驱动而非硬编码的方式, / A) _; Z, a3 k% T 那么策略变更和维护都会方便得多。事实上,如果过程是数据驱动的,# }! x% ]* O3 c7 O/ n8 y) f7 `+ `
你就可以把相当大的责任推给用户,由用户来维护自己的工作流过程。 ) Z- f, t, N ~& O 2 A2 Y/ ~& J# M6 v0 ?1 m ■ 标准化不能过头5 N: `) _) A B$ e u