今天 主要谈谈数据库设计技巧
认为不能不先谈数据结构。 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
2
类别 1 1 010000
3
类别 1.1 2 010100
4
类别 1.2 2 010200
5
类别 2 1 020000
6
类别 2.1 5 020100
7
类别 3 1 030000
8
类别 3.1 7 030100
9
类别 3.2 7 030200
10
类别 1.1.1 3 010101
现在按 type_layer 大小来检索一下: SELECT * FROM Type_table_2 ORDER BY type_layer
列出记录集如下:
type_id type_name type_father type_layer
1
总类别 0 000000
2
类别 1 1 010000
3
类别 1.1 2 010100
10
类别 1.1.1 3 010101
4
类别 1.2 2 010200
5
类别 2 1 020000
6
类别 2.1 5 020100
7
类别 3 1 030000
8
类别 3.1 7 030100
9
类别 3.2 7 030200
现在列出的记录顺序正好是先序遍历的结果。控制显示类别的层次时,只要对 type_layer 字段中的数值进行判断,每 2 位一组,如大于 0 则向右移 2 个空格。当然,这个例子中设定的限制条件是最多 3 层,每层最多可设 99 个子类别,只要按用户的需求情况修改一下 type_layer 长度和位数,即可更改限制层数和子类别数。其实,上面的设计不单单只在类别表中用到网上某些可按树型列表显示的论坛顺序大多采用类似的设计。