- 浏览: 745864 次
- 性别:
- 来自: 湖北
-
文章分类
最新评论
-
SE_XiaoFeng:
用mysqldump命令行导出。这个报错唉。错误提示信息如下: ...
linux下如何导入导出MySQL数据库 -
SE_XiaoFeng:
文章写的干脆了当,我喜欢!
linux下如何导入导出MySQL数据库 -
niky6688:
网站咋打不开呢
beckham herms birki ...
【原创】上周给公司新做了一个网站,请大家审阅! -
niky6688:
哈哈
new chanel bags 2012
burbe ...
今天我抢了一个咪咪??? -
ydsakyclguozi:
...
jsp资源管理器也可能是木马
说到数据库,我认为不能不先谈数据结构。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的长度和位数,即可更改限制层数和子类别数。其实,上面的设计不单单只在类别表中用到,网上某些可按树型列表显示的论坛程序大多采用类似的设计。
或许有人认为,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_name | char(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)(待续)
发表评论
-
几种常用数据库比较
2010-09-08 08:08 1110目前,商品化的数据库 ... -
MySQL出错代码列表
2010-02-03 12:44 5401005:创建表失败 ... -
linux下如何导入导出MySQL数据库
2009-12-23 11:27 5197一、导出: 用mysqldump命令行 命令格 ... -
SQL操作全集
2009-12-03 18:04 643SQL操作全集 下 ... -
MySQL导入导出.sql文件步骤如下
2009-12-01 16:11 1158一.MySQL的命令行模式 ... -
java调用mysql命令 导入导出数据库
2009-11-25 17:05 1904具体的相关类 及 驱动文件 见 附件 package ... -
SQL命令导入导出大全
2009-11-22 14:39 1506EXEC master..xp_cmdshell ’b ... -
MySQL 建表语法
2009-11-20 13:37 16721、最简单的: CREATE TAB ... -
insert into select 复制表
2009-11-05 14:39 1103insert into 目标表 (pw ) select pw ... -
MySQL:MySQL 创建存储过程(MySQL 5.0)
2009-11-04 17:32 1372MySQL 存储过程是从 MySQL ... -
SQL Server 高效分页,没有比这更好的了!
2009-11-04 17:18 2479-- @PageNo : 第几页 -- @PageSize ... -
MySQL中将一个表数据批量导入另一表
2009-11-04 16:50 1827不管是在网站开发还是在应用程序开发中,我们经常会碰到需要将My ... -
MySQL字段类型的选择与MySQL的查询效率
2009-10-21 23:35 2185要选择有助于使查询执 ... -
三种数据库利用SQL语句进行高效果分页
2009-10-21 23:33 902在程序的开发过程中,处理分页是大家接触比较频繁的事件,因为现在 ... -
MySQL查询及删除重复记录的方法
2009-10-21 15:51 1821(一) 1、查找表中多余的重复记录,重复记录是根据单个字段(p ... -
mysql数据库中常见错误提示及解决方法
2009-10-15 18:26 1470mysql数据库中常见错误提示及解决方法 phpma.com ... -
自动增长字段
2009-10-12 16:32 1093Oracle 1、建用户数据表 drop ... -
无法连接 远程IP上的mysql 数据库???
2009-09-09 18:04 2428如果你想连接你的mysql的时候发生这个错误: 以下是引用内 ... -
SQL精华收集
2009-08-24 18:39 1024SQL精华收集 order by 的数值型灵活使用 selec ... -
mysql 5.0存储过程学习总结
2009-05-13 22:18 1016一.创建存储过程 1.基本语法: create proce ...
相关推荐
理解数据库设计的基本原理,如数据表的创建、数据的增删改查,以及关系数据库的概念,对提高后端开发能力非常有帮助。 此外,《细说PHP》还可能包含对PHP中常用的设计模式的介绍,设计模式是解决软件设计中常见问题...
内容涵盖了PHP的运行环境搭建、Web服务器Apache的配置与应用、动态网站开发的前台技术、PHP编程语言的语法、PHP的常用功能模块和实用技巧、MySQL数据库的设计与应用、PHP 5面向对象的程序设计思想、Web开发的设计...
内容涵盖了PHP的运行环境搭建、Web服务器Apache的配置与应用、动态网站开发的前台技术、PHP编程语言的语法、PHP的常用功能模块和实用技巧、MySQL数据库的设计与应用、PHP 5面向对象的程序设计思想、Web开发的设计...
书中关于MySQL的章节,将引导读者学习数据库设计的基础原则,掌握SQL语句的编写技巧,如何高效地进行数据的增删改查操作,以及如何通过数据库连接和事务处理来提升数据管理的稳定性和安全性。这些数据库知识的掌握,...
尽管文件名看起来像是一个网站的介绍,但实际内容可能包含PHP编程相关的实例,例如如何使用PHP进行用户注册、登录系统的设计、数据验证、会话管理等。这个文件可能展示了如何将PHP与数据库结合,实现一个简单的婚恋...
内容涵盖了动态网站开发的前台技术(HTML+CSS)、PHP编程语言的语法、PHP的常用功能模块和实用技巧、MySQL数据库的设计与应用、PHP面向对象的程序设计思想、数据库抽象层PDO、Smarty模板技术、Web开发的设计模式、...
内容涵盖了动态网站开发的前台技术(HTML+CSS)、PHP编程语言的语法、PHP的常用功能模块和实用技巧、MySQL数据库的设计与应用、PHP面向对象的程序设计思想、数据库抽象层PDO、Smarty模板技术、Web开发的设计模式、...
11. PHP高级话题:包括命名空间、设计模式、PHP的垃圾回收机制、性能优化技巧等,帮助读者深入理解PHP的内在工作原理。 12. PHP框架介绍:简述一些流行的PHP框架,如Laravel、Symfony、Yii等,以及它们在实际项目中...
9. **数据库交互**:PDO和mysqli扩展的使用,SQL查询的执行流程,以及事务处理和预编译语句。 10. **会话管理**:PHP的session机制,包括会话存储、会话ID生成和管理、会话超时等。 11. **CLI模式**:除了Web应用...
源码可能包含对数组的各种操作,如创建、遍历、排序、搜索等,这有助于理解数据组织和处理的技巧。 4. PHP文件系统操作:PHP可以用来读写文件、目录操作、文件上传下载等。源码中可能会涉及这些功能的实现,让你...
11. **MySQL数据库设计**:测试了SQL语句的使用,包括SELECT、INSERT、UPDATE和DELETE,以及索引、视图和存储过程的创建。 12. **PHP的mysqli扩展**:使用mysqli进行数据库连接、查询和事务处理,以及预处理语句和...
在"高洛峰细说PHP第二版配套源码"中,你可以找到与书中各个章节对应的示例代码,这些代码涵盖了PHP的基础语法、面向对象编程、数据库操作、Web开发、错误处理、函数库应用等多个方面。 1. PHP基础语法:源码中包含...
这些内容在第二版中会有详细阐述,通过源码分析,读者可以更直观地理解面向对象的设计模式。 3. PHP函数库:PHP拥有丰富的内置函数库,涵盖字符串处理、数组操作、文件系统操作、网络通信等多个方面。附加章节可能...
《PHP细说17章信息发布系统》是一套专为初学者设计的学习资源,它涵盖了从基础到实践的全面PHP知识,旨在帮助新手快速掌握PHP编程技能,并能够构建一个实际的信息发布系统。在这个系统中,你将了解到如何利用PHP语言...
内容涵盖了PHP的运行环境搭建、Web服务器Apache的配置与应用、动态网站开发的前台技术、PHP编程语言的语法、PHP的常用功能模块和实用技巧、MySQL数据库的设计与应用、PHP 5面向对象的程序设计思想、Web开发的设计...
5. **《MySQL Cookbook》**:类似于《PHP Cookbook》,但专注于MySQL的操作和优化技巧,非常适合希望深入了解MySQL数据库管理的开发者。 通过阅读这些书籍,不仅可以获得PHP与MySQL Web开发所需的理论知识和技术...
5. **学习资源**:由于这是韩顺平老师的教学实例,所以源码中应该包含详细的注释和指导,便于学习者理解代码逻辑和应用技巧,提升自身的JSP和JavaMail技术水平。 在【压缩包子文件的文件名称列表】中,尽管没有具体...
本教程以实例驱动,通过一系列精心设计的项目,逐步引导读者熟悉和掌握Visual C++ 6.0的各项功能和编程技巧。首先,你会了解到如何安装和配置Visual C++ 6.0 IDE,包括设置编译器选项、创建新工程以及管理源代码文件...
10. **其他资源**:还包括了张诚的UI视频教程、经典版PHP视频教程、《细说PHP》第二版光盘的内容,以及关于求职和面试技巧的“明哥聊求职”系列。 这些资源不仅适合自学,也适合作为教学资料,涵盖了从Web前端到...
经验04 数据库设计经验谈 经验05 项目实战经验谈 第2篇 陷阱或谬误篇 第3章 不可忽视的30个技术陷阱 陷阱01 版本不一致产生的陷阱 陷阱02 结构初始化产生的陷阱 陷阱03 传递派生类产生的陷阱 陷阱04 用DataReader...