[转]如何优化数据系统----面对数据冗余
发信人: hunter__fox(雁回西楼)整理人: hunter__fox(2002-05-21 10:06:01)
注:今天无意中翻到了这篇文章,最近在做个数据库管理系统,因为是新手,以前没做过,碰到了很多问题,特别是数据库建立不规范的问题,看完这篇文章获益良多,特转过来给大家参考参考。高手可以补充补充,新手学习学习,大家共同提高,谢谢!
从关系数据据的原理来看,是不应当存在数据重复这一现象的。那么,为什么我们的数据库里为什么常常会出现重复的数据呢?我们应当怎样在这一方面来优化数据结构呢?
首先,让我们看看数据库里出现重复记录的特征吧。如果你的代码里常常出现下面所所述的内容,那么,就证明你的数据库结构有必要进行优化。
一、常常需要使用 RecNo() 这样的函数来取得记录号以便进一步获取一条记录中的数据。
二、数据库中的表很少,基本上一条记录就是一组相对很完整的数据信息,一般情况下,读取信息,不需要从多个表中进行查找。
三、很多时候,在 Browse 或 Grid 中看到的数据表,里面有很多记录的同一字段内容相同或大部分相同。
四、很少使用组合查询或视图。
五、数据库很快就膨胀起来,以至于不得不经常将相对较旧数据从数据库中移出。
六、常常需要使用 Append From Array 这样的批次添加的命令来操作数据库中的记录。
七、表格字段数很多。
八、表格中存在相同含义或相近含义的字段。
九、数据库中存在很多与其它表无关联的表格。
下面,我们针对以上各种情况,具体分析各自的起因,并通过进一步的挖掘数据之间的关系,来找出一个优化的办法。
对第一种情况,即,使用绝对记录号的问题。关系数据据库中,从一个最朴素的思想出发,我们可以得出这样一个结论:一个数据库中的数据,是互相关联的。因此,应当没有不能通过这种数据与数据之间的关联来定位的数据记录。在使用 SQL Server 时,很少有机会让我们使用 绝对记录号来操作数据记录,更通常的情况是,我们通过一组表达式来确定我们需要操作的数据对象。在 SQLServer 中,我们的一个表中,如果出现两条完全想同的记录,那么,这个表就很可能再也无法正常使用了――你无法再通过一个表达式来更改其中一条记录。
因此,我们在对于 VFP本身的数据表进行操作时,也应当铭记这样一点:没有完全相同的记录。只要存在不同,我们就可以通过不同之处将它们区分开来,而不必使用 RecNo() 这样的绝对记录号来做这样的事。RecNo() 的作用不是用来在存取数据时定位记录的,它在 VFP中提供出来,是作为另一种用途的,很可惜,没有多少书籍能够提到这一点,以至于初学 VFP的朋友,因为它的好用,而失去了建立正确的关系数据系统的概念。
所以,第一点,我们应当使用表达式来定位记录,而不是用绝对记录号。当然,特殊情况下的例外也是存在的。
对于第二种情况,一个表格存放一套完整的信息,在初学 VFP时,的确很好用,因为它可让我们的代码更加简单,我们不需要操作多个表,每一种操作,可能都只需要对一个表进行操作,这是从简单到复杂的一个过程。但如果我们只停留在这种水平上,那么,我们就失去了进一步提高自己的数据库设计能力了。这种数据结构的设计,并没有体现出关系数据库中各种数据之间的真正的关系,而只是笼统的将数据硬塞进数据库已。可以想象,在若干时日之后,这种设计方式的弊端暴露出来,整个系统的性能和稳定性将会受到多么大的影响。因为所有有关系的数据在一起,当我们只需要其中极少的一个数据时,我们可能需要访问很多的数据,才能得到我们想要的数据。这对于一个灵巧的数据系统来说,是不能忍受的。因此,我们应当将数据库中所有没有必然关系的数据都分开。一个简单的例子就是员工信息。员工信息可能包含很多字段,例如编号,姓名,年龄,籍贯,身份证号,学历,毕业时间,就职时间,就职前工作时间,职务,性别,婚姻状况以及个人简历,介绍人,加薪记录等等,初时的设计,当然是将它们用一个表存放,这样,我们可以很容易的访问其中任何一部分信息----因为在设计时,我们用于测试的数据库,包含的数据一般都不大,速度还不是不能忍受的。一旦我们在数据库中真的这样做了,那么,随着开发的进一步深入,我们发现,更多是情况下,我们并不是在使用整个数据,使用最多的,是姓名和职务以及编号。那么,我们不是不可以将它们单独作为一个表来存放呢?设想一下,当你的数据库里有了一千个员工的信息时---(上表所有信息在一起,一条记录可能需要一百多字节)在其它地方,我们常常只需要员工姓名,职务和编号(那就只有16字节),其中的数据利用率不到百分之二十。换句话说,我们将这一部分单独作为一个表,将可使系统在这一地方的效率提高五倍。什么样的数据才应该区分开呢?这里有一个强关联与弱关联的区别。当一种信息在极多的情况下,总是各另一种信息在一起使用,那么,它们之间的关系就是强关联,这种情况下,应当将它们存放在一起,这是不用再想的。而弱关联则是指那些在逻辑上存在一定关联,但在使用中却并不一起使用的数据。很明显,弱关系应当在物理上区分开来,就像上表中,毕业时间和就职时间可以分开存放一样。所以,第二点,我们应当在明确数据之间的关系后一步的明确它们是强关联还是弱关联。
对于第三种情况,有部分可在第二步时就解决――因为它们本是一种数据。另一种情况,就是因为这里的数据是一种多选数据,即,可让用户从一个列表框中来选择的数据。对于他们,如果字段长度小于四字节,那么,可以考虑不理会它们,如果数据长度大于四字节,就可以考虑用一个ID字段一将它们简化。在我的系统中,我常用一个表格来专门存放这类数据――因为它们的数量一般都不多,单独存放似乎有点浪费,这个表我用了这样上字段:(ID i字段区分不同的类型,每一种多选,拥有一个不同的Type值,这样,就在很多地主看不到那些字段了,在财务系统中,常常出现很多相同的报帐名称,它们大多相同,但又不固定,我们就可以用这种方法来解法这一问题,相同的东西,我就让他们只存在一次,表中,只有它们的一个索引号,如果你愿意,甚至索引字段也只用两个字节或一个字节。因此,对于第三种情况,我们可以通过对相同的内容建立索引表来减小它们占用的空间――而且,索引字段是数值型,有利于搜索。
第四种情况,就是一个很基本的事情了。从 FoxBase过来的人,在开始很长一段时间里,对视图这个东东是不很感冒的。而 VFP作为专用数据库系统开发平台,如果没有使用好视图和Select - SQL语句中的组合查询,那就等于是拿着机枪当鞭炮,浪费资源了。我看到一个朋友,学用Delphi,将一个表中的数据过滤出来,他使用Do语句――我不为他悲哀,我为Delphi感到悲哀,一个很好的数据平台,如果这样使用,还不如不用它,用 Excel也许更好。在 VFP中,我们应当尽可能的使用那些内置的 SQL语句,一来,它们确实与SQL Server是标准语法很相近,二来,它们的效率的确很高,十万条记录以内,它们的速度绝对是一流的。因此,在能用它们完成任务的情况下,应当将它们作
为首选。使用它们,操作的数据,一般不会用 RecNo()这样的函数的,因此,可以确保你的数据是按条件来选择的,而不是记录号。
数据膨胀的问题,其实在很大程度上是因为数据不够精练。对于一个日期值使用什么格式,一般人会选用日期型字段来存放。其实,更好的办法是使用一个I 型字段来存放。首先,这样让数据的长度减小了一半。另外,这样的数值使用加减运算更直观,我一直这样认为,日期的可加减,并不是开发平台的一个很好的功能,作为对其它开发平台的代码共用,不使用日期直接进行加减应当是一个正确的决定。数据的膨胀,还存在于多表数据雷同上。当一个表中存放了一组信息,在另一个表中存放经过修改的信息,这样只会增加数据管理的复杂,无利于系统的进一步提升性能。排除这种雷同,首先需要对数据系统进行一个完整的分析,弄清楚各种数据是怎样从原始数据转变成为结果数据的,然后才有可能决定,什么样的数据应当保存,什么样的数据不用保存――它们可以在运行时轻易的得到。并不是所有的原始数据都值得保留。当它们只生成一组结果数据的时候,或者说,当没有使用它们生成多组数数据时,它们就没有必要再保留。有两个例子可以作一个简单的说明。考勤系统中,刷卡时间仅生成一个结果数据,那就是一个刷卡号与刷卡时间的对应表,那么,在生成这个对应表后,就没有必要再保留刷卡的原始数据了。而人事系统中,生日这一项,可从身份证号中得到,似乎没有必要保留,但因为身份证中有很多误填的情况,加上农历与公历的不同选择,它们并不是完全有关的,因此,不能说生日这一项就一定来自于身份证号,不能将它从员工信息表中排除(当然,如果系统不需要生日这一信息的话就不用说了)。
第六点看来与主题无多大关系。但事实上,这一命令是一个很不好的命令,我个人认为,这样一个命令,并不能让系统能更好,相反,它带来了很多不必要的数据。一个数组的数据,一般并不是全部由用户输入的信息,更多的时候,它来自于其它一个表。从第五条我们知道,能自其它地方得到的数据,应当避免存放在表中,那么,我们完全有理由认为,使用 Append From Array这样的命令是不好的数据内容的开始。我们在成批的添加数据时,应当仔细的考虑是否有这样做的必要。任何一种重复,对于数据系统来说,都是一种额外的负担――你改其中一处数据时,也要同步修改其它部份的数据。这是很不划算的一种做法。一个数据系统正常运行的过程是,最常用的情况是一条记录一条记录的添加数据的,成批的添加数据,是很少见的一种行为,看一看网易的论坛,这么多数据,难道是成批的添加上来的吗?不要以为很快能得到很多数据是一件好事。相反,它是一个让人十分担忧的现象,因为它将让你的数据系统很快成为一个大胖子――因为营养过剩。 第七点,表格中字段数很多。一旦字段数多了起来,你就有必要再审视一下这个表的所有数据是否永远在一起使用。很多字段的表格,查询起来,费时也相应的多,但这还不是重点。重点是,这里面很可能就存在重复的内容。化整为零的方案,看来是增加了字段的总量,但在实际使用中,常常能让数据变得更为精练和灵活。还是以人事表为例,将它分为三个表或四个表,应当是一个很好的选择:最常用的姓名、职务和编号作为一个表,身份信息作为一个表,在厂内的信息作为一个表,而那些备注型的内容,如简介、调职记录、奖惩记录则可作为一个表(其实这个表里后两字段的内容用其它方式保存更好)。事实上,化整为零的做法,也能减小整个数据库的大小。
曾看到一个表格,用来保存员工在厂内的床位信息的,因为一个房间有十六个床位,就有人用了一个十七字段的表格来保存这一信息,一个字段是宿舍号,另外十六个字段就是分别存放一号床到十六号床的使用者。这种情况下,数据的重复情况虽然没有了,但是――编程中的代码要怎么写呢?如果要寻找某人住在哪里,岂不是要:
Select 房号 ;
From 住宿表 ;
Where 床1="某某" Or 床2="某某" Or 床3="某某" ...
那么,如果我的工厂是用一种很大的集体宿舍,一个房间里是五十个床,那怎么是好?再夸张一点,一间房是二百五十四个床,岂不是将一个表的二百五十四个字段用完还不够么?很简单的三个字段就能搞定的数据信息,在这里,就成了一个很不可想象的样子(当然,使用三字段表也不是最好的解决办法)。朋友们可以看看,自己的数据库里,是否存在这样的表呢?也许,没这么夸张,但只要有两个字段相同,就在必要重新设计表的结构了。
第九点,说到表格之间的关联。这并不是要说我们在设计数据库时,就一定要将近表的关系用永久联接连起来。我们可以用代码来建立临时的关联。但是有一点,那就是表格的关系一定要明确。任何一个完整的数据系统,都将是由一个完全互相关联的数据来构成的。没有哪一种信息能够例外。如果你的数据库里存在两组相互独立的数据,那么,你应当将它们分别安置在不同的数据库中,而不是一个。这对于建立一个完整的数据系统,是十分重要的一步。设计数据结构时,一定要尽可能的将数据间的种种互动关系弄清楚,不要急于去建立数据实体和写代码,那只是最后的工作。一个成功的数据库,在设计完成后,应当是很少改动的,不要因为设计时没有考虑到某些情况,而在写代码的过程中或代码完成后去改动它,那样做,只会让这个系统越来越混乱。曾有一个公司让我为它写一个人事系统,他们的经理问我需我多长时间,我说最少得三个月,而且那是我没有其它的事的情况下。那经理最后找到另一个人来开发这个系统,只用了一个月。但事后,他们因为这个系统又找那位开发者很多次,只是因为现实中的某些情况这个系统不能实现。这个系统最后在使用了十一个月后宣告正式停用。开发者和使用者都对它很失望。开发者说这个公司的要求太多与标准系统不同,而使用者说这个系统不能适应公司内的制度,虽然公司数次调整制度来适应它。而事实上,并不是开发人员的能力问题,也不是公司制度的问题,归根结底的看,还是在开始阶段对现有的人工系统的数据流程没有弄清,以致于需要不断的修正。
说了这么多废话,其实,看一看,好象也没讲出什么来,乱七八糟的说一大堆,也不知各位朋友在这方面的看法如何?请各自发表一下自己的见解吧。
[ 本帖最后由 lyxc34 于 2011-7-9 09:42 编辑 ]