浅谈数据库设计技巧.docx

上传人:b****1 文档编号:2030165 上传时间:2023-05-02 格式:DOCX 页数:13 大小:24KB
下载 相关 举报
浅谈数据库设计技巧.docx_第1页
第1页 / 共13页
浅谈数据库设计技巧.docx_第2页
第2页 / 共13页
浅谈数据库设计技巧.docx_第3页
第3页 / 共13页
浅谈数据库设计技巧.docx_第4页
第4页 / 共13页
浅谈数据库设计技巧.docx_第5页
第5页 / 共13页
浅谈数据库设计技巧.docx_第6页
第6页 / 共13页
浅谈数据库设计技巧.docx_第7页
第7页 / 共13页
浅谈数据库设计技巧.docx_第8页
第8页 / 共13页
浅谈数据库设计技巧.docx_第9页
第9页 / 共13页
浅谈数据库设计技巧.docx_第10页
第10页 / 共13页
浅谈数据库设计技巧.docx_第11页
第11页 / 共13页
浅谈数据库设计技巧.docx_第12页
第12页 / 共13页
浅谈数据库设计技巧.docx_第13页
第13页 / 共13页
亲,该文档总共13页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

浅谈数据库设计技巧.docx

《浅谈数据库设计技巧.docx》由会员分享,可在线阅读,更多相关《浅谈数据库设计技巧.docx(13页珍藏版)》请在冰点文库上搜索。

浅谈数据库设计技巧.docx

浅谈数据库设计技巧

 浅谈数据库设计技巧

说到数据库,我认为不能不先谈数据结构。

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*FROMType_table_2ORDERBYtype_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的长度和位数,即可更改限制层数和子类别数。

其实,上面的设计不单单只在类别表中用到,网上某些可按树型列表显示的论坛程序大多采用类似的设计。

  或许有人认为,Type_table_2中的type_father字段是冗余数据,可以除去。

如果这样,在插入、删除某个类别的时候,就得对type_layer的内容进行比较繁琐的判定,所以我并没有消去type_father字段,这也正符合数据库设计中适当保留冗余数据的来降低程序复杂度的原则,后面我会举一个故意增加数据冗余的案例。

  二、商品信息表的设计

  假设你是一家百货公司电脑部的开发人员,某天老板要求你为公司开发一套网上电子商务平台,该百货公司有数千种商品出售,不过目前仅打算先在网上销售数十种方便运输的商品,当然,以后可能会陆续在该电子商务平台上增加新的商品出售。

现在开始进行该平台数据库的商品信息表的设计。

每种出售的商品都会有相同的属性,如商品编号,商品名称,商品所属类别,相关信息,供货厂商,内含件数,库存,进货价,销售价,优惠价。

你很快就设计出4个表:

商品类型表(Wares_type),供货厂商表(Wares_provider),商品信息表(Wares_info):

商品类型表(Wares_type)

名称     类型    约束条件                      说明

type_id    int      无重复                    类别标识,主键

type_name  char(50)   不允许为空                  类型名称,不允许重复

type_father  int        不允许为空                  该类别的父类别标识,如果是顶节点的话设定为某个唯一值

type_layer   char(6)    限定3层,初始值为000000      类别的先序遍历,主要为减少检索数据库的次数

供货厂商表(Wares_provider)

名称     类型    约束条件                      说明

provider_id  int      无重复                    供货商标识,主键

provider_namechar(100)  不允许为空                  供货商名称

商品信息表(Wares_info)

名称     类型    约束条件                      说明

wares_id      int     无重复                      商品标识,主键

wares_name    char(100) 不允许为空                    商品名称

wares_type  int       不允许为空          商品类型标识,和Wares_type.type_id关联

wares_info    char(200) 允许为空                      相关信息

provider      int       不允许为空                    供货厂商标识,和Wares_provider.provider_id关联

setnum        int       初始值为1                     内含件数,默认为1

stock         int       初始值为0                     库存,默认为0

buy_price     money     不允许为空                    进货价

sell_price    money     不允许为空                    销售价

discount      money     不允许为空                    优惠价

  你拿着这3个表给老板检查,老板希望能够再添加一个商品图片的字段,不过只有一部分商品有图片。

OK,你在商品信息表(Wares_info)中增加了一个haspic的BOOL型字段,然后再建了一个新表——商品图片表(Wares_pic):

商品图片表(Wares_pic)

名称     类型    约束条件                      说明

pic_id       int      无重复                      商品图片标识,主键

wares_id     int        不允许为空                    所属商品标识,和Wares_info.wares_id关联

pic_address char(200)  不允许为空          图片存放路径

  程序开发完成后,完全满足老板目前的要求,于是正式启用。

一段时间后,老板打算在这套平台上推出新的商品销售,其中,某类商品全部都需添加“长度”的属性。

第一轮折腾来了……当然,你按照添加商品图片表的老方法,在商品信息表(Wares_info)中增加了一个haslength的BOOL型字段,又建了一个新表——商品长度表(Wares_length):

商品长度表(Wares_length)

名称     类型    约束条件                      说明

length_id    int      无重复                      商品图片标识,主键

wares_id     int        不允许为空                    所属商品标识,和Wares_info.wares_id关联

length      char(20)   不允许为空          商品长度说明

  刚刚改完没多久,老板又打算上一批新的商品,这次某类商品全部需要添加“宽度”的属性。

你咬了咬牙,又照方抓药,添加了商品宽度表(Wares_width)。

又过了一段时间,老板新上的商品中有一些需要添加“高度”的属性,你是不是开始觉得你所设计的数据库按照这种方式增长下去,很快就能变成一个迷宫呢?

那么,有没有什么办法遏制这种不可预见性,但却类似重复的数据库膨胀呢?

我在阅读《敏捷软件开发:

原则、模式与实践》中发现作者举过类似的例子:

7.3 “Copy”程序。

其中,我非常赞同敏捷软件开发这个观点:

在最初几乎不进行预先设计,但是一旦需求发生变化,此时作为一名追求卓越的程序员,应该从头审查整个架构设计,在此次修改中设计出能够满足日后类似修改的系统架构。

下面是我在需要添加“长度”的属性时所提供的修改方案:

  去掉商品信息表(Wares_info)中的haspic字段,添加商品额外属性表(Wares_ex_property)和商品额外信息表(Wares_ex_info)2个表来完成添加新属性的功能。

商品额外属性表(Wares_ex_property)

名称     类型    约束条件                      说明

ex_pid       int      无重复                      商品额外属性标识,主键

p_name       char(20)   不允许为空                    额外属性名称

商品额外信息表(Wares_ex_info)

名称       类型    约束条件                      说明

ex_iid         int      无重复                      商品额外信息标识,主键

wares_id       int        不允许为空                    所属商品标识,和Wares_info.wares_id关联

property_id   int        不允许为空          商品额外属性标识,和Wares_ex_property.ex_pid关联

property_value char(200)  不允许为空                    商品额外属性值

  在商品额外属性表(Wares_ex_property)中添加2条记录:

ex_pid           p_name

1               商品图片

2               商品长度

  再在整个电子商务平台的后台管理功能中追加一项商品额外属性管理的功能,以后添加新的商品时出现新的属性,只需利用该功能往商品额外属性表(Wares_ex_property)中添加一条记录即可。

不要害怕变化,被第一颗子弹击中并不是坏事,坏的是被相同轨道飞来的第二颗、第三颗子弹击中。

第一颗子弹来得越早,所受的伤越重,之后的抵抗力也越强8)(待续)

  三、多用户及其权限管理的设计

  开发数据库管理类的软件,不可能不考虑多用户和用户权限设置的问题。

尽管目前市面上的大、中型的后台数据库系统软件都提供了多用户,以及细至某个数据库内某张表的权限设置的功能,我个人建议:

一套成熟的数据库管理软件,还是应该自行设计用户管理这块功能,原因有二:

  1.那些大、中型后台数据库系统软件所提供的多用户及其权限设置都是针对数据库的共有属性,并不一定能完全满足某些特例的需求;

  2.不要过多的依赖后台数据库系统软件的某些特殊功能,多种大、中型后台数据库系统软件之间并不完全兼容。

否则一旦日后需要转换数据库平台或后台数据库系统软件版本升级,之前的架构设计很可能无法重用。

  下面看看如何自行设计一套比较灵活的多用户管理模块,即该数据库管理软件的系统管理员可以自行添加新用户,修改已有用户的权限,删除已有用户。

首先,分析用户需求,列出该数据库管理软件所有需要实现的功能;然后,根据一定的联系对这些功能进行分类,即把某类用户需使用的功能归为一类;最后开始建表:

  

功能表(Function_table)

名称     类型    约束条件   说明

f_id         int      无重复    功能标识,主键

f_name       char(20)   不允许为空  功能名称,不允许重复

f_desc       char(50)   允许为空    功能描述

用户组表(User_group)

名称     类型    约束条件   说明

group_id     int        无重复       用户组标识,主键

group_name   char(20)   不允许为空   用户组名称

group_power  char(100)  不允许为空   用户组权限表,内容为功能表f_id的集合

用户表(User_table)

名称     类型    约束条件   说明

user_id      int        无重复       用户标识,主键

user_name    char(20)   无重复       用户名

user_pwd     char(20)   不允许为空   用户密码

user_type    int        不允许为空   所属用户组标识,和User_group.group_id关联

  采用这种用户组的架构设计,当需要添加新用户时,只需指定新用户所属的用户组;当以后系统需要添加新功能或对旧有功能权限进行修改时,只用操作功能表和用户组表的记录,原有用户的功能即可相应随之变化。

当然,这种架构设计把数据库管理软件的功能判定移到了前台,使得前台开发相对复杂一些。

但是,当用户数较大(10人以上),或日后软件升级的概率较大时,这个代价是值得的。

  四、简洁的批量m:

n设计

  碰到m:

n的关系,一般都是建立3个表,m一个,n一个,m:

n一个。

但是,m:

n有时会遇到批量处理的情况,例如到图书馆借书,一般都是允许用户同时借阅n本书,如果要求按批查询借阅记录,即列出某个用户某次借阅的所有书籍,该如何设计呢?

让我们建好必须的3个表先:

书籍表(Book_table)

名称     类型    约束条件   说明

book_id      int        无重复       书籍标识,主键

book_no      char(20)   无重复       书籍编号

book_name    char(100)  不允许为空   书籍名称

……

借阅用户表(Renter_table)

名称     类型    约束条件   说明

renter_id    int        无重复       用户标识,主键

renter_name  char(20)   不允许为空   用户姓名

……

借阅记录表(Rent_log)

名称     类型    约束条件   说明

rent_id      int        无重复       借阅记录标识,主键

r_id         int        不允许为空   用户标识,和Renter_table.renter_id关联

b_id         int        不允许为空   书籍标识,和Book_table.book_id关联

rent_date    

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2