浅谈数据库设计技巧(上)

2008-04-02 10:30:19来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

  说到数据库,我认为不能不先谈数据结构。1996年,在我初入大学学习电脑编程时,当时的老师就告诉我们说:电脑程式=数据结构+算法。尽管现在的程式研发已由面向过程为主逐步过渡到面向对象为主,但我还是深深赞同8年前老师的告诉我们的公式:电脑程式=数据结构+算法。面向对象的程式研发,要做的第一件事就是,先分析整个程式中需处理的数据,从中提取出抽象模板,以这个抽象模板设计类,再在其中逐步添加处理其数据的函数(即算法),最后,再给类中的数据成员和函数划分访问权限,从而实现封装。

  数据库的最初雏形据说源自美国一个奶牛场的记账薄(纸质的,由此可见,数据库并不一定是存储在电脑里的数据),里面记录的是该奶牛场的收支账目,程式员在将其整理、录入到电脑中时从中受到启发。当按照规定好的数据结构所采集到的数据量大到一定程度后,出于程式执行效率的考虑,程式员将其中的检索、更新维护等功能分离出来,做成单独调用的模块,这个模块后来就慢慢发展、演变成现在我们所接触到的数据库管理系统(DBMS)——程式研发中的一个重要分支。

  下面进入正题,首先按我个人所接触过的程式给数据库设计人员的功底分一下类:
  1、没有系统学习过数据结构的程式员。这类程式员的作品往往只是他们的即兴玩具,他们往往习惯只设计有限的几个表,实现某类功能的数据全部塞在一个表中,各表之间几乎毫无关联。网上不少的免费管理软件都是这样的东西,当程式功能有限,数据量不多的时候,其程式运行起来没有什么问题,但是假如用其管理比较重要的数据,风险性很大。
  2、系统学习过数据结构,但是还没有研发过对程式效率需要比较高的管理软件的程式员。这类人多半刚从学校毕业不久,他们在设计数据库表结构时,严格按照教科书上的规定,死扣E-R图和3NF(别灰心,任何的数据库设计高手都是从这一步开始的)。他们的作品,对于一般的access型轻量级的管理软件,已够用。但是一旦该系统需要添加新功能,原有的数据库表差不多得进行大换血。
  3、第二类程式员,在经历过数次程式效率的提升,连同功能升级的折腾后,终于升级成为数据库设计的老鸟,第一类程式员眼中的高人。这类程式员能够胜任二十个表以上的中型商业数据管理系统的研发工作。他们知道该在什么样的情况下保留一定的冗余数据来提高程式效率,而且其设计的数据库可拓展性较好,当用户需要添加新功能时,原有数据库表只需做少量修改即可。
  4、在经历过上十个类似数据库管理软件的重复设计后,第三类程式员中坚持下来没有转行,而是希望从中找出“偷懒”窍门的有心人会慢慢觉悟,从而完成量变到质变的转换。他们所设计的数据库表结构有一定的远见,能够预测到未来功能升级所需要的数据,从而预先留下伏笔。这类程式员现在大多晋级成数据挖掘方面的高级软件研发人员。
  5、第三类程式员或第四类程式员,在对现有的各家数据库管理系统的原理和研发都有一定的钻研后,要么在其基础上进行二次研发,要么自行研发一套有自主版权的通用数据库管理系统。

  我个人正处于第三类的末期,所以下面所列出的一些设计技巧只适合第二类和部分第三类数据库设计人员。同时,由于我很少碰到有兴趣在这方面深钻下去的同行,所以文中难免出现错误和遗漏,在此先行声明,欢迎大家指正,不要藏私哦8)

  一、树型关系的数据表
  不少程式员在进行数据库设计的时候都碰到过树型关系的数据,例如常见的类别表,即一个大类,下面有若干个子类,某些子类又有子类这样的情况。当类别不确定,用户希望能够在任意类别下添加新的子类,或删除某个类别和其下的任何子类,而且预计以后其数量会逐步增长,此时我们就会考虑用一个数据表来保存这些数据。按照教科书上的教导,第二类程式员大概会设计出类似这样的数据表结构:

类别表_1(Type_table_1)
名称     类型    约束条件   说明
type_id     int      无重复   类别标识,主键
type_name   char(50)  不允许为空 类型名称,不允许重复
type_father   int   不允许为空 该类别的父类别标识,假如是顶节点的话设定为某个唯一值

  这样的设计短小精悍,完全满足3NF,而且能够满足用户的任何需要。是不是这样就行呢?答案是NO!Why?

  我们来估计一下用户希望如何罗列出这个表的数据的。对用户而言,他当然期望按他所设定的层次关系一次罗列出任何的类别,例如这样:
总类别
  类别1
    类别1.1
      类别1.1.1
    类别1.2
  类别2
    类别2.1
  类别3
    类别3.1
    类别3.2
  ……

  看看为了实现这样的列表显示(树的先序遍历),要对上面的表进行多少次检索?注意,尽管类别1.1.1可能是在类别3.2之后添加的记录,答案仍然是N次。这样的效率对于少量的数据没什么影响,但是日后类型扩充到数十条甚至上百条记录后,单单列一次类型就要检索数十次该表,整个程式的运行效率就不敢恭维了。或许第二类程式员会说,那我再建一个临时数组或临时表,专门保存类型表的先序遍历结果,这样只在第一次运行时检索数十次,再次罗列任何的类型关系时就直接读那个临时数组或临时表就行了。其实,用不着再去分配一块新的内存来保存这些数据,只要对数据表进行一定的扩充,再对添加类型的数量进行一下约束就行了,要完成上面的列表只需一次检索就行了。下面是扩充后的数据表结构:

类别表_2(Type_table_2)
名称     类型    约束条件    说明
type_id     int      无重复   类别标识,主键
type_name   char(50)   不允许为空 类型名称,不允许重复
type_father    int    不允许为空 该类别的父类别标识,假如是顶节点的话设定为某个唯一值
type_layer    char(6) 限定3层,初始值为000000 类别的先序遍历,主要为减少检索数据库的次数

  按照这样的表结构,我们来看看上面例子记录在表中的数据是怎样的:

type_id type_name type_father type_layer
1 总类别 0 000000

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:SQL语句中的一些特殊参数如何用变量来代替

下一篇: 浅谈数据库设计技巧(下)