精选了其中的 60 个最佳技巧,并把这些技巧编写成了本文,为了方便索引其内容划分为 5 个部分:# K, X. f" A7 p" i& `
上一部分介绍了设计数据库之前12个基本技巧,包括命名规范和明确业务需求等( 数据库设计经验谈[1])。本次第二部分介绍设计数据库表24个指南性技巧,涵盖表内字段设计以及应该避免的常见问题等。# H4 H9 Q) g- m4 h1 o
第 2 部分 - 设计表和字段0 T( H; w. h/ V' }% Q, _& g
检查各种变化
# A9 s$ X# D0 e 我在设计数据库的时候会考虑到哪些数据字段将来可能会发生变更。比方说,姓氏就是如此(注意是西方人的姓氏,比如女性结婚后从夫姓等)。所以,在建立系统存储客户信息时,我倾向于在单独的一个数据表里存储姓氏字段,而且还附加起始日和终止日等字段,这样就可以跟踪这一数据条目的变化。
2 m% n C- i; m' Q. I% L 采用有意义的字段名
; r/ Z( u1 P- z 有一回我参加开发过一个项目,其中有从其他程序员那里继承的程序,那个程序员喜欢用屏幕上显示数据指示用语命名字段,这也不赖,但不幸的是,她还喜欢用一些奇怪的命名法,其命名采用了匈牙利命名和控制序号的组合形式,比如 cbo1、txt2、txt2_b 等等。, x& L" `- ^6 X4 N5 \
除非你在使用只面向你的缩写字段名的系统,否则请尽可能地把字段描述的清楚些。当然,也别做过头了,比如 Customer_Shipping_Address_Street_Line_1,虽然很富有说明性,但没人愿意键入这么长的名字,具体尺度就在你的把握中。. r) V. T- q Z8 n. I
采用前缀命名7 V1 s, V7 U' Y' b8 N3 G6 L
如果多个表里有好多同一类型的字段(比如 FirstName),你不妨用特定表的前缀(比如 CusLastName)来帮助你标识字段。! U0 T) J1 n, M7 ]. @3 i
时效性数据应包括“最近更新日期/时间”字段。时间标记对查找数据问题的原因、按日期重新处理/重载数据和清除旧数据特别有用。7 i% e( M0 F1 Y. {& |+ h8 F) {
标准化和数据驱动* C- y2 `! ^- I, _& [
数据的标准化不仅方便了自己而且也方便了其他人。比方说,假如你的用户界面要访问外部数据源(文件、XML 文档、其他数据库等),你不妨把相应的连接和路径信息存储在用户界面支持表里。还有,如果用户界面执行工作流之类的任务(发送邮件、打印信笺、修改记录状态等),那么产生工作流的数据也可以存放在数据库里。预先安排总需要付出努力,但如果这些过程采用数据驱动而非硬编码的方式,那么策略变更和维护都会方便得多。事实上,如果过程是数据驱动的,你就可以把相当大的责任推给用户,由用户来维护自己的工作流过程。& b& o( s' A9 C6 G5 Q, y
标准化不能过头
, a1 |$ m+ A* o- R' R1 P 对那些不熟悉标准化一词(normalization)的人而言,标准化可以保证表内的字段都是最基础的要素,而这一措施有助于消除数据库中的数据冗余。标准化有好几种形式,但 Third Normal Form(3NF)通常被认为在性能、扩展性和数据完整性方面达到了最好平衡。简单来说,3NF 规定:
( g7 n0 w6 \9 t u* f5 m. I * 表内的每一个值都只能被表达一次。7 N2 ?1 d8 h- m7 F# s% J
* 表内的每一行都应该被唯一的标识(有唯一键)。
/ O# l8 s( B! ?* f+ Q * 表内不应该存储依赖于其他键的非键信息。0 h/ G& q3 W5 v7 L' Z( H) l, m
遵守 3NF 标准的数据库具有以下特点:有一组表专门存放通过键连接起来的关联数据。比方说,某个存放客户及其有关定单的 3NF 数据库就可能有两个表:Customer 和 Order。Order 表不包含定单关联客户的任何信息,但表内会存放一个键值,该键指向 Customer 表里包含该客户信息的那一行。
# g5 X* T/ N7 y" Y6 y( Z 更高层次的标准化也有,但更标准是否就一定更好呢?答案是不一定。事实上,对某些项目来说,甚至就连 3NF 都可能给数据库引入太高的复杂性。
6 P" k; A$ D- t; @ _ 为了效率的缘故,对表不进行标准化有时也是必要的,这样的例子很多。曾经有个开发餐饮分析软件的活就是用非标准化表把查询时间从平均 40 秒降低到了两秒左右。虽然我不得不这么做,但我绝不把数据表的非标准化当作当然的设计理念。而具体的操作不过是一种派生。所以如果表出了问题重新产生非标准化的表是完全可能的。
, |) B, U% K/ C8 _4 f Microsoft Visual FoxPro 报表技巧
( |. P7 B! X5 C2 J( i4 \ 如果你正在使用 Microsoft Visual FoxPro,你可以用对用户友好的字段名来代替编号的名称:比如用 Customer Name 代替 txtCNaM。这样,当你用向导程序 [Wizards,台湾人称为‘精灵’] 创建表单和报表时,其名字会让那些不是程序员的人更容易阅读。2 O0 ]1 x# ^ K0 o, q& e
不活跃或者不采用的指示符
8 k. @% L& t3 @" W' {: x1 Q c 增加一个字段表示所在记录是否在业务中不再活跃挺有用的。不管是客户、员工还是其他什么人,这样做都能有助于再运行查询的时候过滤活跃或者不活跃状态。同时还消除了新用户在采用数据时所面临的一些问题,比如,某些记录可能不再为他们所用,再删除的时候可以起到一定的防范作用。" V0 y/ l7 [, _: i; ?# n
使用角色实体定义属于某类别的列[字段]
# S1 y0 I6 e& u- o 在需要对属于特定类别或者具有特定角色的事物做定义时,可以用角色实体来创建特定的时间关联关系,从而可以实现自我文档化。2 U3 Q. v( z, P2 @! |% J \
这里的含义不是让 PERSON 实体带有 Title 字段,而是说,为什么不用 PERSON 实体和 PERSON_TYPE 实体来描述人员呢?比方说,当 John Smith, Engineer 提升为 John Smith, Director 乃至最后爬到 John Smith, CIO 的高位,而所有你要做的不过是改变两个表 PERSON 和 PERSON_TYPE 之间关系的键值,同时增加一个日期/时间字段来知道变化是何时发生的。这样,你的 PERSON_TYPE 表就包含了所有 PERSON 的可能类型,比如 Associate、Engineer、Director、CIO 或者 CEO 等。
; Y) A, M( I* s# c7 S3 b( z6 H, D 还有个替代办法就是改变 PERSON 记录来反映新头衔的变化,不过这样一来在时间上无法跟踪个人所处位置的具体时间。 |