yanglilibaobao/
共986个网摘 [
1 2 3 4 5 6 ...
33 ]
下一页 |
访问yanglilibaobao的个人空间
yanglilibaobao收录,使用标签:数据库,时间:2007-8-16 9:59:32 | 相关网摘,我也收藏
一、概述
随着数据库在各个领域的使用不断增长,越来越多的应用提出了高性能的要求。数据库性能调优是知识密集型的学科,需要综合考虑各种复杂的因素:数据库缓冲区的大小、索引的创建、语句改写等等。总之,数据库性能调优的目的在于使系统运行得更快。
调优需要有广泛的知识,这使得它既简单又复杂。
说调优简单,是因为调优者不必纠缠于复杂的公式和规则。许多学术界和业界的研究者都在尝试将调优和查询处理建立在数学基础之上。
称调优复杂,是因为如果要完全理解常识所依赖的原理,还需要对应用、数据库管理系统、操作系统以及硬件有广泛而深刻的理解。
数据库调优技术可以在不同的数据库系统中使用。如果需要调优数据库系统,最好掌握如下知识:1)查询处理、并发控制以及数据库恢复的知识;2)一些调优的基本原则。
这里主要描述索引调优。
二、索引调优
索引是建立在表上的一种数据组织,它能提高访问表中一条或多条记录的特定查询效率。因此,适当的索引调优是很重要的。
对于索引调优存在如下的几个误区:
误区1:索引创建得越多越好?
实际上:创建的索引可能建立后从来未使用。索引的创建也是需要代价的,对于删除、某些更新、插入操作,对于每个索引都要进行相应的删除、更新、插入操作。从而导致删除、某些更新、插入操作的效率变低。
误区2:对于一个单表的查询,可以索引1进行过滤再使用索引2进行过滤?
实际上:假设查询语句如下select * from t1 where c1=1 and c2=2,c1列和c2列上分别建有索引ic1、ic2。先使用ic1(或ic2)进行过滤,产生的结果集是临时数据,不再具有索引,所以不可使用ic2(或ic1)进行再次过滤。
索引优化的基本原则:
1.将索引和数据存放到不同的文件组
没有将表数据和索引数据存储到不同的文件组,而不加区别地将它们存储到同一文件组。这样,不但会造成I/O竞争,也为数据库的维护工作带来不变。
2.组合索引的使用
假设存在组合索引it1c1c2(c1,c2),查询语句select * from t1 where c1=1 and c2=2能够使用该索引。查询语句select * from t1 where c1=1也能够使用该索引。但是,查询语句select * from t1 where c2=2不能够使用该索引,因为没有组合索引的引导列,即,要想使用c2列进行查找,必需出现c1等于某值。
根据where条件的不同,归纳如下:
1) c1=1 and c2=2:使用索引it1c1c2进行等值查找。
2) c1=1 and c2>2:使用索引it1c1c2进行范围查找,可以有两种方法。
方法1,使用通过索引键(1,2)在B树中命中一条记录,然后向后扫描找出 第一条符合条件的记录,从此记录往后的每一条记录都是符合条件的。这种方法的弊端在于:如果c1=1 and c2=2对应的记录数很多,会产生很多无效的扫描。
方法2,如果c2对应的int型数据,可以使用索引键(1,3)在B树中命中一条记录,从此记录往后的每一条记录都是符合条件的。
本文中的例子均采用方法1。
3)c1>1 and c2=2:因为索引的第一个列不是等于号的,索引即使后面出现了c2=2,也不能将c2=2应用于索引查找。这里,通过索引键(1,- ∞)在B树中命中一条记录,向后扫描找出第一条符合c1>1的记录,此后的每一条记录判断是否符合c2=2,如果符合则输出,否则过滤掉。这里我们称c2=2没有参与到索引运算中去。这种情况在实际应用中经常出现。
4)c1>1:通过索引键(1,- ∞) 在B树中命中一条记录,以此向后扫描找出第一条符合c1>1的记录,此后的每条记录都是符合条件的。
3.唯一索引与非唯一索引的差异
假设索引int1c1(c1)是唯一索引,对于查询语句select c1 from t1 where c1=1,达梦数据库使用索引键(1)命中B树中一条记录,命中之后直接返回该记录(因为是唯一索引,所以最多只能有一条c1=1的记录)。
假设索引it1c2(c2)是非唯一索引,对于查询语句select c2 from t2 where c2=2,达梦数据库使用索引键(2)命中B树中一条记录,返回该记录,并继续向后扫描,如果该记录是满足c=2,返回该记录,继续扫描,直到遇到第一条不符合条件c2=2的记录。
于是,我们可以得知,对于不存在重复值的列,创建唯一索引优于创建非唯一索引。
4.非聚集索引的作用
每张表只可能一个聚集索引,聚集索引用来组织真实数据。语句“create table employee (id int cluster primary key,name varchar(20),addr varchar(20))”。表employee的数据用id来组织。如果要查找id=1000的员工记录,只要用索引键(1000)命中该聚集索引。但是,对于要查找name=’张三’的员工记录就不能使用该索引了,需要进行全表扫描,对于每一条记录判断是否满足name=’张三’,这样会导致查询效率非常低。
要使用聚集索引,必需提供id,我们只能提供name,于是需要引入一个辅助结构实现name到id的转换,这就是非聚集索引的作用。该非聚集索引的键是name,值是id。于是语句“select * from employee where name=’张三’”的执行流程是:通过键(’张三’)命中非聚集索引,得到对应的id值3(假设’张三’对应的id为3),然后用键(3)命中聚集索引,得到相应的记录。
5.是不是使用非聚集索引的查询都需要进行聚集的查询?
不是的,虽然在上一点中查询转换为聚集索引的查找,有时候可以只需要使用非聚集索引。
创建表并创建相应的索引:create table t1(c1 int,c2 int,c3 int);create index it1c2c3 on t1(c2,c3)。查询语句为:select c3 from t1 where c2=1。
因为索引it1c2c3(c2,c3)覆盖查询语句中的列(c2,c3)。所以,该查询语句的执行流程为:通过索引键(1,- ∞)命中索引it1c2c3,对于该记录直接返回c3对应的值,继续向后扫描,如果索引记录中c1还是等于1,那么输出c3,以此类推,直到出现第一条c1不等于1的索引记录,结束查询。
6.创建索引的规则
创建索引首先要考虑的是列的可选择性。比较一下列中唯一键的数量和表中记录的行数,就可以判断该列的可选择性。如果该列的“唯一键的数量/表中记录行数”的比值越接近于1,则该列的可选择行越高。在可选择性高的列上进行查询,返回的数据就较少,比较适合索引查询。相反,比如性别列上只有两个值,可选择行就很小,不适合索引查询。
http://news.csdn.net/n/20070816/107539.html
yanglilibaobao收录,使用标签:数据库,时间:2007-8-15 17:47:13 | 相关网摘,我也收藏
一、概述
这篇文章是数据库性能调优技术的第二篇。上一篇讲解的索引调优是数据库性能调优技术的基础。这篇讲解的深入理解单表执行计划,是数据库性能调优的有力工具。
查询语句可以有多种可选执行计划,如何选择效率最高的执行计划?达梦数据库、oracle数据库、sql server数据库都是采用基于成本的查询优化,对备选执行计划进行打分,选择大家最小的执行计划进行执行。这些内容,我会在后续的几篇文章中进行详细的描述。在此之前,我们首先需要掌握如何理解数据库执行计划。这篇文章讲解只涉及单表操作的执行计划。
达梦数据库、oracle数据库、sql server数据库都可以显示给定语句的执行计划。我详细分析了这三个数据库的执行计划,三者之间并无本质区别。
所以本文的内容适合于这三个数据库。同样,也应该适合绝大多数其它的数据库。
单表执行的深入理解,是了解多表执行计划的基础。达梦数据库显示的执行计划时,显示的信息会多一些。
因此,这篇文章中我选择达梦数据库作为实例数据库来讲解执行计划的原理。
读完本文后,应该能够读懂这三个数据库的单表执行计划。
二、深入理解数据库执行计划
达梦数据库的执行计划有两种显示方式:第一种为图形化的显示方式;第二种为文本式的显示方式。这里采用第二种方式进行讲解。
理解执行计划,是迈向理解数据库性能调优的重要一步。从执行计划中,我们可以看出数据库是如何执行查询语句,并根据执行计划判断出该查询语句的执行是否高效,以及如何进行优化。
下面我们将通过一些例子来理解数据库执行计划。
1.没有索引的全表扫描过滤如何执行?
构造处执行场景:
create table t1(c1 int,c2 int);
insert into t1 values(1,1);
insert into t1 values(2,2);
insert into t1 values(3,3);
insert into t1 values(4,4);
insert into t1 values(5,5);
insert into t1 values(6,6);
查询语句为:
select * from t1 where c1=2;
该语句的执行过程,如果用语言描述可以描述成这样:
1)如果是第一次执行该步骤,则取得表的第一条记录;否则取得当前记录的下一条记录。如果记录已经扫描结束,则执行步骤4,否则执行步骤2。
2)判断该记录是否满足过滤条件c1=2,满足则执行步骤3,否则执行步骤1。
3)把该记录放到结果集中,执行步骤1。
4)将结果集返回给客户端。
实际上,数据库执行查询语句的过程也是类似的,下面是该查询语句的执行计划:
#RSET:[21, 1, 1];
#XFLT:[0, 0, 0]; EXPR0 = 2
#CSEK:[21, 1, 1]; INDEX33555545(T1), FULL_SCAN
该执行计划中出现的内容,在此做出解释:
1)CSEK(查找)类似于上文中描述的步骤1,方括号中的内容是执行该操作的评估代价,本文不作分析。“INDEX33555545(T1)”说明使用了T1表的聚集索引,“FULL_SCAN”表示对聚集索引INDEX33555545(T1)进行全扫描。
这里需要注意的是,达梦数据库中的表默认情况下是索引组织的。如果建表时指定了cluster primary key,那么数据以该clsuter primary key组织数据,否则以rowid组织数据。
2)XFLT(过滤)类似于上文中描述的步骤2,“EXPR0 = 2”是过滤条件。
3)RSET(结果集)类似于上文中描述的步骤3,用来存放符合条件的记录集。
我们可以看出,数据库的执行过程和我们用语言描述的步骤是一致的。
该查询语句完整的执行流程如下:
1)CSEK取得第一条记录(1,1)传给XFLT,将控制权传给XFLT。
2)XFLT发现该记录(1,1)不符合条件,将控制权传给CSEK。
3)CSEK取得下一条记录(2,2)传给XFLT,将控制权传给XFLT。
4)XFLT发现记录(2,2)符合条件,将该记录传给RSET,将控制权传给RSET。
5)RSET将记录(2,2)放入结果集,将控制权传给XFLT。
6)XFLT给控制权传给CSEK。
7)CSEK取得下一条(3,3)传给XFLT,将控制权传给XFLT。
8)XFLT发现该记录(3,3)不符合条件,将控制权传给CSEK。
9)CSEK取得下一条(4,4)传给XFLT,将控制权传给XFLT。
10)XFLT发现该记录(4,4)不符合条件,将控制权传给CSEK
11)CSEK取得下一条(5,5)传给XFLT,将控制权传给XFLT。
12)XFLT发现该记录(5,5)不符合条件,将控制权传给CSEK。
13)CSEK取得下一条(6,6)传给XFLT,将控制权传给XFLT。
14)XFLT发现该记录(6,6)不符合条件,将控制权传给CSEK。
15)CSEK发现描述操作已经结束,通知XFLT结束。将控制权传给XFLT。
16)XFLT得知查询操作结束,通知RSET结束。将控制权传给RSET。
17)RSET得知操作结束。
18)发送结果集(包含记录(2,2))给客户端。
2.如果表t1上的c1列有非唯一索引,如何执行呢?
表t1的定义以及数据和1中描述的一样。
创建索引:
create index it1c1 on t1(c1);
查询语句“select * from t1 where c1=2;”对应的执行计划为:
#RSET:[201, 2, 1];
#CSEK(SECOND):[201, 2, 1]; IT1C1(T1), INDEX_EQU_SEARCH
CSEK行的“SECOND”表示使用非聚集索引“IT1C1”,对该索引进行索引等值(INDEX_EQU_SEARCH)查找。
该执行计划的执行流程为:
1)CSEK使用c1=2查找非聚集索引,得到第一条c1=2的索引记录(2,rowid1)中的rowid1(为数值)。使用rowid1查找聚集索引得到对应的数据记录(2,2)传递给RSET,将控制权传给RSET。
2)RSET将记录(2,2)放入结果集,将控制权传给CSEK。(因为c1上的索引是非唯一的,所以可能出现两条以上的记录满足c1=2,所以需要将控制权传给CSEK)。
3)CSEK取得当前非聚集记录的下一条记录(3,rowid2),因为3!=2,所以扫描结束。将控制权传给RSET。(如果满足c1=2的记录数大于1条,需要继续传递记录给RSET,以此类推,直到遇到不满足c1=2的那条记录,结束操作。)
4)RSET得知操作结束。
5)发送结果集(包含记录(2,2))给客户端。
3.如果表t1上的c1列有唯一索引,如何执行呢?
首先删除c1列上的非唯一索引,然后在c1列上创建唯一索引:
drop index it1c1;
create unique index uit1c1 on t1(c1);
查询语句“select * from t1 where c1=2;”对应的执行计划为:
#RSET:[201, 2, 1];
#CSEK(SECOND):[201, 2, 1]; UIT1C1(T1), INDEX_EQU_SEARCH
该执行计划的执行流程为:
1)CSEK使用c1=2查找非聚集索引,得到c1=2的索引记录(2,rowid1)中的rowid1(为数值)。使用rowid1查找聚集索引得到对应的数据记录(2,2)传递给RSET,将控制权传给RSET。(当然,有人也许会问,如果没有记录满足c1=2怎么办呢?那么,此处什么记录都不传递给RSET,通知RSET查询操作结束,最后返回空集给客户端)。
2)RSET将记录(2,2)放入结果集,操作结束(因为是唯一索引,所以最多只有1条记录满足c1=2)。
3)发送结果集(包含记录(2,2))给客户端。
这里我们发现,例3使用了唯一索引,例2使用了非唯一索引。例3的执行速度大于例2的执行速度。
4.如何理解执行计划中的top n操作?
查询语句“select top 10 * from t1 where c1〉2;”对应的执行计划为:
#RSET:[21, 1, 1];
#XTOP:[0, 0, 0]; top_off(0), top_num(10)
#XFLT:[0, 0, 0]; EXPR1 〉 2
#CSEK:[21, 1, 1]; INDEX33555545(T1), FULL_SCAN
XTOP(取得前N条记录):将XFLT操作符传递来的记录放入到RSET(结果集)中,并判断记录数是否已经等于给定值10(语句中的top 10)。如果已经等于10,则查询已经执行成功,退出。否则将控制权限传给XFLT,继续执行。依次执行,直到取得10条记录,或者表CSEK操作已经查询结束(即符合条件的记录不满10条)。
5.如何理解执行计划中的order by操作?
查询语句“select top 10 * from t1 where c2〉2 order by c1;”对应的执行计划为:
#RSET:[21, 1, 1];
#XSORT:[0, 0, 0]; keys_num(1), is_distinct(FALSE)
#XFLT:[0, 0, 0]; EXPR1 〉 2
#CSEK:[21, 1, 1]; INDEX33555545(T1), FULL_SCAN
XSORT(对记录进行排序):将XFLT操作符传递来的记录插入到XSORT维护的临时空间中的合理位置,按c1进行有序排列。然后将控制权传给XFLT以取得下一条符合条件的记录。等处理完所有符合条件的记录。XSORT操作符才会将控制权限传给RSET。
6.是不是查询语句中一旦出现order by字句,执行计划中就会出现XSORT操作符?
不是。
比如,查询语句“select c1 from t1 order by c1;”对应的执行计划为:
#RSET:[0, 0, 0];
#CSEK:[0, 0, 0]; UIT1C1(T1), FULL_SCAN
从执行中我们可以看出,达梦直接对索引UIT1C1进行全索引扫描,对于得到的每一条记录不需要进行XSORT排序操作,直接放入RSET(结果集)中。因为索引UIT1C1本身就是按照c1进行排序的。
7.有文档说,对于语句“select max(c1) from t1”,可以在c1列上创建索引从而查询速度变快。那么在执行计划中是如何体现的呢?
查询语句“select max(c1) from t1”对应的执行计划:
#RSET:[0, 0, 0];
#XEVL:[0, 0, 0];
#FAGR:[0, 0, 0]; function_num(1)
在这个执行计划中,我们没有看到CSEK操作符。因为c1上存在索引UIT1C1,该索引叶子节点的最右端就是c1的最大值。FARG直接返回该最大值。语句“select min(c1) from t1;”、语句“select count(*) from t1;”的执行原理一样。XEVL是表达式计算,本文不进行讲解。
8.如果列上存在索引,如何理解中的group by操作?
查询语句“select c1,count(*) from t1 where c1〉=2 group by c1;”对应的执行计划为:
#RSET:[11, 1, 1];
#XEVL:[0, 0, 0];
#SAGR:[0, 0, 0]; group_by_num(1), function_num(1)
#CSEK:[11, 1, 1]; UIT1C1(T1), INDEX_GE_SEARCH
我们可以得到,CSEK使用了索引UIT1C1进行了范围查找。首先传递给SARG的是连续的c1=2的记录组,然后是c1=3的记录组,然后是c1=4的记录组,……
此处SARG的执行流程是
1)从CSEK取得一条c1=2记录,将计数加1,
2)从CSEK取得下一条记录,如果该记录满足c1,将计数+1。
3)重复执行步骤2,直到取得第一条不满足c1=2的记录,将(2,对应的计算)传递给XEVL,再传给RSET(结果集)。接着对c1=3的记录组执行同样的流程。依此类推,直到处理完所有符合条件的记录。
这里我们的分组函数是count(*),如果是其它的分组函数,处理过程类似。
9.如果列上不存在索引,如何理解中的group by操作?
查询语句“select c2,count(*) from t1 where c2〉=2 group by c2;”对应的执行计划为:
#RSET:[21, 1, 1];
#XEVL:[0, 0, 0];
#HAGR:[0, 0, 0]; group_by_num(1), function_num(1)
#XFLT:[0, 0, 0]; EXPR0 〉= 2
#CSEK:[21, 1, 1]; INDEX33555550(T1), FULL_SCAN
这里因为c2上没有索引,HARG的作用是HASH分组。
HARG的执行流程是:
1)从XFLT取得一条记录
2)记录的c1=m,如果在hash表中已经对应项,计数+1,如果不存在对应项,在创建一个新的hash项。
3)所有的符合过滤条件的记录处理完成之后,HARG才会将控制权限传给上层操作符,HARG每次向上层操作符传递一条(m,m对应的计数)。
这里我们的分组函数是count(*),如果是其它的分组函数,处理过程类似。
http://news.csdn.net/n/20070815/107516.html
yanglilibaobao收录,使用标签:数据库,时间:2007-8-7 9:51:31 | 相关网摘,我也收藏
关系数据库设计之时是要遵守一定的规则的。尤其是数据库设计范式现简单介绍1NF(第一范式),2NF(第二范式),3NF(第三范式)和BCNF,另有第四范式和第五范式留到以后再介绍。在你设计数据库之时,若能符合这几个范式,你就是数据库设计的高手。
第一范式(1NF):在关系模式R中的每一个具体关系r中,如果每个属性值都是不可再分的最小数据单位,则称R是第一范式的关系。例:如职工号,姓名,电话号码组成一个表(一个人可能有一个办公室电话和一个家里电话号码)规范成为1NF有三种方法:
一是重复存储职工号和姓名。这样,关键字只能是电话号码。
二是职工号为关键字,电话号码分为单位电话和住宅电话两个属性
三是职工号为关键字,但强制每条记录只能有一个电话号码。
以上三个方法,第一种方法最不可取,按实际情况选取后两种情况。
第二范式(2NF):如果关系模式R(U,F)中的所有非主属性都完全依赖于任意一个候选关键字,则称关系R 是属于第二范式的。
例:选课关系 SCI(SNO,CNO,GRADE,CREDIT)其中SNO为学号, CNO为课程号,GRADEGE 为成绩,CREDIT 为学分。由以上条件,关键字为组合关键字(SNO,CNO)
在应用中使用以上关系模式有以下问题:
a.数据冗余,假设同一门课由40个学生选修,学分就重复40次。
b.更新异常,若调整了某课程的学分,相应的元组CREDIT值都要更新,有可能会出现同一门课学分不同。
c.插入异常,如计划开新课,由于没人选修,没有学号关键字,只能等有人选修才能把课程和学分存入。
d.删除异常,若学生已经结业,从当前数据库删除选修记录。某些门课程新生尚未选修,则此门课程及学分记录无法保存。
原因:非关键字属性CREDIT仅函数依赖于CNO,也就是CREDIT部分依赖组合关键字(SNO,CNO)而不是完全依赖。
解决方法:分成两个关系模式 SC1(SNO,CNO,GRADE),C2(CNO,CREDIT)。新关系包括两个关系模式,它们之间通过SC1中的外关键字CNO相联系,需要时再进行自然联接,恢复了原来的关系
第三范式(3NF):如果关系模式R(U,F)中的所有非主属性对任何候选关键字都不存在传递信赖,则称关系R是属于第三范式的。
例:如S1(SNO,SNAME,DNO,DNAME,LOCATION)各属性分别代表学号,
姓名,所在系,系名称,系地址。
关键字SNO决定各个属性。由于是单个关键字,没有部分依赖的问题,肯定是2NF。但这关系肯定有大量的冗余,有关学生所在的几个属性DNO,DNAME,LOCATION将重复存储,插入,删除和修改时也将产生类似以上例的情况。
原因:关系中存在传递依赖造成的。即SNO -> DNO。而DNO -> SNO却不存在,DNO -> LOCATION, 因此关键辽 SNO 对 LOCATION 函数决定是通过传递依赖 SNO -> LOCATION 实现的。也就是说,SNO不直接决定非主属性LOCATION。
解决目地:每个关系模式中不能留有传递依赖。
解决方法:分为两个关系 S(SNO,SNAME,DNO),D(DNO,DNAME,LOCATION)
注意:关系S中不能没有外关键字DNO。否则两个关系之间失去联系。
BCNF:如果关系模式R(U,F)的所有属性(包括主属性和非主属性)都不传递依赖于R的任何候选关键字,那么称关系R是属于BCNF的。或是关系模式R,如果每个决定因素都包含关键字(而不是被关键字所包含),则RCNF的关系模式。
例:配件管理关系模式 WPE(WNO,PNO,ENO,QNT)分别表仓库号,配件号,职工号,数量。有以下条件
a.一个仓库有多个职工。
b.一个职工仅在一个仓库工作。
c.每个仓库里一种型号的配件由专人负责,但一个人可以管理几种配件。
d.同一种型号的配件可以分放在几个仓库中。
分析:由以上得 PNO 不能确定QNT,由组合属性(WNO,PNO)来决定,存在函数依赖(WNO,PNO) -> ENO。由于每个仓库里的一种配件由专人负责,而一个人可以管理几种配件,所以有组合属性(WNO,PNO)才能确定负责人,有(WNO,PNO)-> ENO。因为一个职工仅在一个仓库工作,有ENO -> WNO。由于每个仓库里的一种配件由专人负责,而一个职工仅在一个仓库工作,有(ENO,PNO)-> QNT。
找一下候选关键字,因为(WNO,PNO) -> QNT,(WNO,PNO)-> ENO ,因此(WNO,PNO)可以决定整个元组,是一个候选关键字。根据ENO->WNO,(ENO,PNO)->QNT,故(ENO,PNO)也能决定整个元组,为另一个候选关键字。属性ENO,WNO,PNO 均为主属性,只有一个非主属性QNT。它对任何一个候选关键字都是完全函数依赖的,并且是直接依赖,所以该关系模式是3NF。
分析一下主属性。因为ENO->WNO,主属性ENO是WNO的决定因素,但是它本身不是关键字,只是组合关键字的一部分。这就造成主属性WNO对另外一个候选关键字(ENO,PNO)的部分依赖,因为(ENO,PNO)-> ENO但反过来不成立,而P->WNO,故(ENO,PNO)-> WNO 也是传递依赖。
虽然没有非主属性对候选关键辽的传递依赖,但存在主属性对候选关键字的传递依赖,同样也会带来麻烦。如一个新职工分配到仓库工作,但暂时处于实习阶段,没有独立负责对某些配件的管理任务。由于缺少关键字的一部分PNO而无法插入到该关系中去。又如某个人改成不管配件了去负责安全,则在删除配件的同时该职工也会被删除。
解决办法:分成管理EP(ENO,PNO,QNT),关键字是(ENO,PNO)工作EW(ENO,WNO)其关键字是ENO
缺点:分解后函数依赖的保持性较差。如此例中,由于分解,函数依赖(WNO,PNO)-> ENO 丢失了, 因而对原来的语义有所破坏。没有体现出每个仓库里一种部件由专人负责。有可能出现一部件由两个人或两个以上的人来同时管理。因此,分解之后的关系模式降低了部分完整性约束。
一个关系分解成多个关系,要使得分解有意义,起码的要求是分解后不丢失原来的信息。这些信息不仅包括数据本身,而且包括由函数依赖所表示的数据之间的相互制约。进行分解的目标是达到更高一级的规范化程度,但是分解的同时必须考虑两个问题:无损联接性和保持函数依赖。有时往往不可能做到既有无损联接性,又完全保持函数依赖。需要根据需要进行权衡。
1NF直到BCNF的四种范式之间有如下关系:
BCNF包含了3NF包含2NF包含1NF
小结:
目地:规范化目的是使结构更合理,消除存储异常,使数据冗余尽量小,便于插入、删除和更新
原则:遵从概念单一化 "一事一地"原则,即一个关系模式描述一个实体或实体间的一种联系。规范的实质就是概念的单一化。
方法:将关系模式投影分解成两个或两个以上的关系模式。
要求:分解后的关系模式集合应当与原关系模式"等价",即经过自然联接可以恢复原关系而不丢失信息,并保持属性间合理的联系。
注意:一个关系模式结这分解可以得到不同关系模式集合,也就是说分解方法不是唯一的。最小冗余的要求必须以分解后的数据库能够表达原来数据库所有信息为前提来实现。其根本目标是节省存储空间,避免数据不一致性,提高对关系的操作效率,同时满足应用需求。实际上,并不一定要求全部模式都达到BCNF不可。有时故意保留部分冗余可能更方便数据查询。尤其对于那些更新频度不高,查询频度极高的数据库系统更是如此。
在关系数据库中,除了函数依赖之外还有多值依赖,联接依赖的问题,从而提出了第四范式,第五范式等更高一级的规范化要求。在此,以后再谈。
各位朋友,你看过后有何感想,其实,任何一本数据库基础理论的书都会讲这些东西,考虑到很多网友是半途出家,来做数据库。特找一本书大抄特抄一把,各位有什么问题,也别问我了,自已去找一本关系数据库理论的书去看吧,说不定,对各位大有帮助。说是说以上是基础理论的东西,请大家想想,你在做数据库设计的时候有没有考虑过遵过以上几个范式呢,有没有在数据库设计做得不好之时,想一想,对比以上所讲,到底是违反了第几个范式呢?
我见过的数据库设计,很少有人做到很符合以上几个范式的,一般说来,第一范式大家都可以遵守,完全遵守第二第三范式的人很少了,遵守的人一定就是设计数据库的高手了,BCNF的范式出现机会较少,而且会破坏完整性,你可以在做设计之时不考虑它,当然在ORACLE中可通过触发器解决其缺点。以后我们共同做设计之时,也希望大家遵守以上几个范式。
http://database.ccidnet.com/art/1105/20070807/1168921_1.html
yanglilibaobao收录,使用标签:数据库,时间:2007-8-7 9:48:16 | 相关网摘,我也收藏
SQL Server 2000 和SQL Server 2005都允许用户恢复整个数据库和选择性的恢复单个的文件或者文件组。这在当有一个特定的文件或者文件组出现问题时,你想不用恢复整个数据库就能恢复失败的文件时是很有用的。而当这些文件或者文件组非常小或者只是数据库的一小部分时就显得尤其有用
这有一个具体例子:如果你有一个单个的出现问题的文件。这个文件有50MB大小,而你的整个数据库运行着大约有几十亿的字节,这样的话如果能恢复单个失败文件的话就显的非常有意义。这样的事情发生的一个情景是当文件或者文件组在单独的驱动器上,而驱动器出现了问题。通常,仅仅恢复单个文件或者文件组会使总的停止时间缩短,因为它明显减少了需要恢复的总的数据量。
现在,为什么你不选择这么做呢?这有一些原因:
你需要有事务日志备份。如果你想从备份中恢复一个文件或者文件组,你同时也需要恢复与它们一起创建的事务记录备份,从而使整个数据库能够处于一个一致的状态。在SQL Server 2000 和 2005中,你需要使用Full Recovery或者Bulk-Logged Recovery模式(也就是说不是Simple Recovery)来使它成为可能。我应该指出SQL Server的实现者们并没有尽他们的努力来完成判断从上一次备份一个文件或者文件组是否已经被修改了的功能。如果没有被改变,那么事务记录是没有什么必要的。但是,总的来说,还是需要事务记录备份的,如果你现在还没有一个备份事务记录的恢复或者备份计划,那么现在就创建一个吧。
在要恢复的文件或者文件组中的表格与数据库中其他的表格之间的数据不一致性成为需要考虑的一个问题。如果你有相互之间依赖的表格,并且这些表格没有被存储在相同的物理文件或者文件组中(这有时是不可避免的),仅仅恢复一个文件或者文件组可能会导致它与数据库其他部分不同步。例如,你有一个表格被另一个表格用JOIN关联,并且这个JOIN使用了一个视图和存储过程,这时仅仅恢复一个而不恢复另一个可能会有问题。
当你在数据库中只有一个文件组。如果你的所有的数据仅仅存储在一个文件或者文件组中,并且它又不是一个特别大的数据库时,会发生什么事情呢?那时恢复一个文件或者文件组的努力就变的没有什么意义了。
选择性的恢复文件或者文件组的主要原因是当恢复数据库很大,以至于恢复整个数据库的代价很大的时候,使得对数据库的局部损坏的恢复成为可能。在一个非常小的轻量级的数据库里,和nonproduction系统中,或者数据库中只有一个文件组的时候,实现选择性的恢复功能就显的没有太大的意义,因为这时恢复整个数据库和恢复单个的文件或者文件组没有什么太大的区别。
我发现大多数时候当人们想使用文件或者文件组恢复时,他们实际上是想把一个特定的表格恢复到先前的一个点的时刻的状态。这在SQL Server中不是一个显式支特的特性,但是存在这么做的方法,倘若你不介意由于采用这种方法而需要手工的来管理可能产生的不一致(就想上面#2所说的)。如果你手边就有一个数据库备份的话,你可以简单的恢复那个备份,仅仅把它看作是相同数据库的不同名字的实例。接着,通过事务记录把数据库向前滚动到指定的点(如果需要这样做的话),然后手工的把当前的数据库拷贝到目标数据库中。
我自己已经实验过这种方法几次,但是仅仅只有一个表格没有与相同数据库中的其他的表格有很大的关联。我的例子涉及了一个包含了留言版系统的聊天网站。我不得不经常恢复一些在留言版上被意外删除的消息,这些是自包含的:从留言版表格的数据产生的唯一的JOINs是外部的而不是内部的。因此,我可以随意的更新表格因为我知道我不会让那个表格与其他表格不同步的。
在SQL Server 2000和它更高的版本中,当你做一个RESTORE操作的时候你可以使用PARTIAL子句,从而使仅仅需要的文件组数据被恢复。这作为一个时间和空间上的节约开销的措施是非常有用的:你不需要进行繁重的恢复所有数据的工作,而仅仅只需要对一个表格进行操作。而且很可能也没有足够的空间来进行完全的恢复操作。
http://searchdatabase.techtarget.com.cn/sqlserver/179/3473679.shtml
yanglilibaobao收录,使用标签:数据库,时间:2007-8-7 9:45:42 | 相关网摘,我也收藏
根据甲骨文以往几个版本的发行经验,发布新版Oracle数据库的频率在3年左右,以此类推,Oracle 11g应该在07年年底发布,选择在7月份发布,不知道是否和代号Katmai的SQL Server 2008有关,因为目前还处于测试阶段的SQL Server 2008将在08年2月发布,业内用Oracle 10g和SQL Server 2003做比较也曾一度惹恼了甲骨文……
未来数据库市场竞争的焦点已不再局限于传统的数据库,新的应用不断赋予数据库新的生命力。
数据库的冰火较量
甲骨文数据库Oracle 11g坚持对网格的支持,但网格计算在中国有点冷。
Gartner公司最近公布了2006全球关系型数据库管理系统市场份额报告,甲骨文的市场份额为47.1%,是全球排名第一的数据库厂商。市场份额继续保持比最接近的两个竞争对手市场份额之和还高的局面。
2007年7月12日,甲骨文公司在美国纽约宣布推出数据库Oracle 11g,这是Oracle数据库的最新版本。甲骨文介绍说,Oracle 11g有400多项功能,经过了1500万个小时的测试,开发工作量达到了3.6万人/月。
有意思的是,根据甲骨文以往几个版本的发行经验,发布新版Oracle数据库的频率在3年左右,以此类推,Oracle 11g应该在07年年底发布,选择在7月份发布,不知道是否和代号Katmai的SQL Server 2008有关,因为目前还处于测试阶段的SQL Server 2008将在08年2月发布,业内用Oracle 10g和SQL Server 2003做比较也曾一度惹恼了甲骨文。
XML显高温
当XML面世之时,也许没有哪个数据库厂商会对这种技术给以足够的关注,然而在今天,XML已经开始对数据存储产生巨大的影响。到现在,这种可扩展标记语言已是各种数据,特别是文档的首选格式,国际主流的数据库厂商们自然也随行就市,全都推出了兼容传统关系型数据与XML数据混合应用的新一代数据库产品。
XML在数据存储方面有一个明显的优点,那就是可以直接将逻辑关系编写在XML文件当中。一个时髦的XML数据库应该提供哪些功能呢?归纳起来应该有四个基本功能:使用、存储、查询和产生XML的能力。
在Oracle 10g中,曾被人们津津乐道的最重要的改进是增加了对XML schema(XML语法)转换的支持,它允许用户通过将现有的数据映射为新的schema来实现XML schema转换。而不必把所有XML数据输出后再重新输入进去,其它事情将由数据库自动完成。
在Oracle 11g中, XML DB的性能又获得很大提高,XML DB是Oracle数据库的一个组件,客户可以以本机方式存储和操作XML数据。11g增加了对二进制XML数据的支持,现在客户可以选择适合自己特定应用及性能需求的XML存储选项。
当然,不仅仅是甲骨文看好XML,为吸引Oracle用户,IBM公司DB2 9打XML旗号直接把XML作为其新产品的最大卖点;微软和Sybase也宣称它们的产品也可以实现高性能XML存储与查询,使现有应用更好地与XML并存。
网格计算有点冷
新的Oracle 11g仍使用g(Grid)作为后缀,以代表这是一个包含了网格技术基础的数据库。甲骨文称,Oracle 11g能更方便地在低成本服务器和存储设备组成的网格上运行。不过,目前仅有IBM DB2数据库也支持网格计算技术。
网格计算将多个服务器和存储器当作一台大型电脑协调使用,使它们在高速网络上动态地共享计算机资源,以满足不断变化的计算需求。简而言之,即将多个服务器和存储器当作一台主机协调使用。网格计算被广泛视为未来的计算方式。
尽管微软对网格计算的兴趣也很浓厚,承诺要让Windows能够更好地适应高数据强度的计算网格。但微软除了在内部研究之外,似乎一直在这个话题上非常沉默。对于数据库中网格计算,微软和Sybase方面表示,网格应用在技术上还需解决一些问题(如:多节点性能问题) ,网格技术要成为商业应用的主流,还需要几年时间在应用和产品上进一步完善。
不容乐观的是,在咨询公司Quocirca发布的调查显示,我国网格实际采用率仍然偏低,总体网格指数在15个被调查国家中只排第9位,处于中下游,甲骨文表示,中国用户可能对网格的价值还没有真正接受。很多中国企业有一种观望的心态,觉得应用网格存在风险。
11g安全了吗?
有业内人士曾表示,Oracle 10g只能算是一个过渡版本。因为06年,下一代安全软件机构NGSS对微软SQL Server和Oracle数据库做了一个弱点对比,结果表明Oracle的数据库产品存在更多的弱点。
NGSS的研究人员称,Oracle有233个缺陷点,而SQL Server只有59个。这些缺陷在SQL Server7、2000以及2005中,在Oracle8、9以及10g版本中被报道,并被修复。分析机构ESG也发布调查报告表示,在安全性方面微软击败了甲骨文,似乎甲骨文数据库“无懈可击”的安全神话已不复存在。
针对那些不断对甲骨文安全性能表示批评的专家,甲骨文终于开始猛烈还击。2006年底,甲骨文全球技术事业部的安全经理Eric Maurice在公司的博客上表示,甲骨文在开发和安全方面的技术水平居业界领先位置。与微软数据库的安全性能比较,不过是别有用心的人在玩数字游戏,甲骨文不会让外部的压力改变其既定的安全策略。
到现在,起码可以从资料上看到,Oracle的安全认证获得最高认证级别的ISO标准认证,而SQL Server并没有获得什么安全认证。从这方面证明了Oracle的安全性不应该被受到如此指责。
从甲骨文此次推出的11g可以看到,在安全方面除了10g已经存在的数据阀门和加密外,11g又增加了四项安全功能,即安全备份、非对称数据的授权安全检索、监控、管理和报警。
Oracle 11g数据库增强了Oracle透明数据加密功能,将这种功能扩展到了卷级加密之外。11g还增加了表空间加密功能,可用来加密整个表、索引和所存储的其它数据。存储在数据库中的大型对象也可以加密。
看来甲骨文很注重11g在安全上的表现,闪回交易技术可以撤销错误交易以及任何相关交易,并行备份和恢复功能。另外,一种新的顾问软件—数据恢复顾问,可自动调查问题,智能地确定恢复计划并处理多种故障情况。
Oracle 11g的Oracle Data Guard组件可用于对生产数据库的报告、备份、测试和“滚动”升级。通过将工作量从生产系统卸载到备用系统,并组成一个更经济的灾难恢复解决方案。
也许正是在安全性上的增强,才使得甲骨文公司数据库服务器技术高级副总裁Andy Mendelsohn自信地表示:“Oracle 11g真正克服了挑战并实现了真正的创新。”
一个疯狂的发烧友在自家的车库中改造了小型IDC,并利用Sun Enterprise 220R Server架设了Oracle 10g数据库
增强信息生命周期管理和存储管理能力:引入了更多的自助式管理和自动化功能;
◆透明的加密:Oracle将这种功能扩展到了卷级加密之外;
◆提高信息可用性:免受计划停机和意外宕机影响;
◆更快的XML:通过XML DB组件,客户可以本机方式存储和操作XML数据;
◆增强了自助式管理和自动化能力:增加了自动SQL和存储器微调等管理功能;
◆增强了应用开发能力:提供多种开发工具供开发人员选择,包括Java实时编译器。
开源数据库成熟时
以MySQL、PostgreSQL为代表的开源数据库系统,已成为取代闭源数据库的一种颇具吸引力的选择。
成熟的开源数据库,让Oracle这样的闭源厂商难以腾飞
知名的网络游戏The Matrix Online(骇客帝国Online),每天有数万名网上玩家同时在线,为了能够支撑庞大的在线游戏玩家同时进行游戏,Sony Online Entertainment(索尼在线娱乐公司,以下简称SOE)需要密集使用数据库。
以往SOE会使用大量的Oracle RAC集群提供服务,但是由于Oracle数据库的授权证十分昂贵及欠缺弹性,加上公司需要更多额外数据库。所以从2005年开始,该公司就开始寻求既具有较低总拥有成本,又具有较好灵活性的开源数据库以取代Oracle数据库。
踢开Oracle
SOE对数据库的需求相当可观,其数据库应用程序是关键任务应用程序的最恰当诠释:每天有数十万在线玩家在玩SOE的游戏,而每款游戏都是一个数据库及其密集的应用程序。
事实上,SOE在应用开放源代码的应用上有很长历史,曾经就使用过Linux、Tomcat、Apache、Hibernate架设系统,此次的开源抉择,SOE更注重寻觅能够利用其宝贵资产(内部能够熟练使用Oracle的数据库人才)的方法,在选择开源数据库时,列出了四项标准:
1、能够充分发挥其现有数据库管理员和开发人员的潜能;
2、易于将SOE现有的Oracle应用程序迁移到新的数据库;
3、能够提供商用级别质量可靠性,包括备份和恢复标准,以支持关键任务应用程序;
4、可扩展,具有高性能。
在选择开源数据库之前,SOE需要使用许多Oracle 9i RAC群集。另外,SOE在其后台运营中部署了数据库。与如今的很多企业一样,SOE希望开源软件能够提供应对这些业务挑战的解决方案。
根据SOE对不同开放源码数据库的评估,他们选择了兼容Oracle数据库的EnterpriseDB,因为SOE有八成以上的特定Oracle应用程式,可以在极少、甚至无需修改的情况下在EnterpriseDB执行,以现有开支比较,利用EnterpriseDB后,每款线上游戏的整体拥有成本可降低80%,每年节省总额过百万,在2007至2008年度,SOE将使用数百台EnterpriseDB数据库集群服务器。
开源更有前途
使用Oracle数据库的企业一般都会对开源数据库感兴趣,主要有三个方面原因:首先,通过部署开源数据库,这些企业可以显著降低数据库的总拥有成本(TCO),有时降幅甚至高达90%;其次,他们通常可以从其他厂商获得更大的许可灵活性以及业务便利;最后,这些企业会发现其他厂商更渴望为他们提供出色技术。
对于开源数据库,企业多少也会有些担心,因为许多企业仅限于将开源数据库用于一些简单的应用程序,如一些网站的支持应用。因为这些企业普遍认为开源数据库可能不够稳定,可靠性或者可扩展性不够高,因而无法满足他们的关键任务应用需求。另外,企业可能还觉得更改数据库的代价,例如,与应用程序重新编码,人员重新培训相关的成本,可能会超出预期的节省目标。
MySQL、FireBird、EnterpriseDB和Postgre(PostgreSQL的前身)都是非常健壮的开源数据库,而EnterpriseDB又是基于PostgreSQL进行开发的,不仅保留了PostgreSQL的稳定性,而且可实现50%的速度增长,系统可以自动监测是否有补丁程序存在,大大减轻管理员的工作。
近几年来,美国一些大企业纷纷采用开放源码数据库,它们往往在总部采用商业数据库,而在分支机构的Linux服务器上采用开源产品。这些数据库除了费用便宜,还各有独到之处。与商业化产品相比,开源数据库结构简单,但功能不简单,读取操作快捷,易管理,甚至不需要全职的管理员。由此吸引了像Cisco、Yahoo这样的大公司,以及众多的中小企业。而在国内,我们熟悉的新浪、网易等大型门户网站也是开源数据库的使用者。
http://searchdatabase.techtarget.com.cn/analysis/215/3475715.shtml
yanglilibaobao收录,使用标签:Java,时间:2007-8-6 17:01:17 | 相关网摘,我也收藏
经常看到不少人抱怨Java EE/J2EE中配置太复杂,烦琐,不简单易学,其实所谓简单易学是取决于你是否有OO思维方式。
分层架构是面向对象OO在企业软件中应用的标志,目前一个企业软件系统包括表现层、业务层和持久层,那么分层架构和OO关系是如何?
表现层的界面表单中通常是一些离散数据,也就是单个字段数据,通过Struts等框架提供ActionForm以及标签库,将这些单个字段数据封装起来和业务层的Domain Model进行了映射,因此,表现层的主要编程工作就是映射配置。
持久层是将Domain Model对象保存到数据库中,过去使用JDBC,我们要逐个打开这些Model对象,然后每个字段逐个 保存到数据库中,如果说表现层框架是实现离散数据封装,那么持久层实现的是反方向:拆封。Hibernate是一个持久层O/R mapping框架, 也就是在对象和关系数据库之间进行映射的框架,EJB的CMP也是类似道理,因此,持久层的主要编程工作也是映射配置。
表现层和持久层这种配置工作就如同打包邮寄一样:你首先要将你的单件用一个箱子包装起来,达到目的地,这个箱子被打开,单件被逐步取出。表现层和持久层这样做的目的是保证中间业务层完全面向对象,保证业务层完全是和一个个对象模型打交道。
在一个真正面向对象的系统中,表现层和持久层是为了将非对象化的数据转为对象。因此,在先进的JavaEE/J2EE架构中,表现层和持久层的主要工作就是配置工作,而且主要是映射mapping的配置。
下面的问题就是:如何解决映射配置简单而且易用,如果拥有正确的指导配置的思维,那么配置工作就容易简单多, 否则,就倍感配置复杂。 那些感觉Java配置复杂的人其实他并没有完整的OO思维。为什么这么说呢?以ORM(Hibernate)配置简易方式说明:
配置的简要之道
首先,配置是映射XML配置,顾名思义,也就是在两者之间做协调,牵线搭桥,说白了,就是做红娘,但和做红娘又有些区别,做红娘可以要求双方做些改变,互相迁就,但是做映射配置,则不能这样,因为那样做就可能做出和需求要求不一样的东西。
配置的简要之道就是:围绕对象模型进行配置;而不是围绕数据表进行配置。
以持久层映射配置来说:存在Domain Model对象和关系数据表,如果感觉在两者之间配置映射很困难,双方做些改变,但是有可能 需求不答应,你一旦为协调而作出的改变可能偏离需求实现的目标,最后作出的系统面貌全非,根本不是客户所需要的。
那么怎么办?很显然,紧扣需求,反映需求的那一方坚决不要变动,那么Domain Model和关系数据表哪一方反映需求呢?按照OO分析,当然 是Domain Model,Model对象我们是依据Evans Model等模型驱动设计MDD概念设计出来,他们是需求的代表。
很显然,我们的映射配置必须顺着Model对象这个思维来配,对于名词式的Model,关联无外乎是其主要关系,当然还有继承,因此,象Hibernate 这些映射配置语法也是面向这些主要对象关系的。
表现层配置也是同样的道理,需要将Domain Model配置成界面表单,在实际中,我们有可能采取的是通过界面收集需求,因此,这个映射配置过程也是考验Model对象是否提炼正确与否,有可能发现Model不能实现一些界面需求功能,这时反过来必须修改我们的Model,而不是仅仅在表现层这个技术层面做些补救措施就糊弄过去。
Java EE/J2EE系统开发过程 敏捷的迭代是必然的。没有一个天才能够一步到位提炼出兼顾界面和数据表以及需求的统一模型出来。
总之,完成一个真正面向对象的Java EE/J2EE系统,必须抓住领域建模和具体框架熟练配置两点,只有这样才能保证Java项目成功实施。最关键的是提炼出反映出业务系统的领域模型:Domain Model,完成业务建模后,就是依赖Struts/Hibernate等配置分配将Model 映射到界面和数据库,其实就是将业务模型移植到计算机领域并能够正确运行。
高聚合和低关联
如果一个系统都被设计成相互没有任何不包含的单个对象,很显然是不能正确反映实际需求的,万事万物都是有其部分组成的,例如窗户由玻璃和框架组成,人是由胳膊 腿等身体部分组成,现实世界中,事物之间总是存在关系,聚合和组成是最常见的。
例如订单,一个订单Orders中由客户名称和地址,订购的产品品种和数量,客户名称和地址我们可以抽象为Customer来代表,产品我们使用Product来代表,由于一个订单中可能订购了多个产品,很显然,一个订单对象中应该有多个Product对象,而且每个Product的数量不一样,我们将Product和其数量再抽象包装成OrderLine订单条目对象,这样,订单中包含多个订单条目,而且订单条目只有依赖某个订单,是其组成部分,是一种强聚合关系,不是普通的聚合或关联关系。而Customer和Order之间是一种聚合关系,如果订单没有客户信息,就不成为订单了。
下面再以用户User这个对象为例,用户User可能拥有很多动态属性,一些属性需要运行时动态确定,用户和动态属性是一个整体和部分的聚合关系;每个用户都必然属于某个部门,因此,用户和部门属性对象之间也是一个整体和部分的聚合关系,这两种聚合关系不同之处在于:前者一个用户可能有多个动态属性,是1:N关系;部门Dept和用户User之间是1:N关系,一个部门中可能有多个用户,反过来说,对于用户User来说:它和部门Dept之间是N:1关系。
通过以上建模过程,我们基本搞清楚两件事:这个领域中存在哪些模型对象?按照Evans的DDD理论,哪些是实体,哪些是值对象;然后我们必须搞清楚那些聚合关系,他们是整体部分的关系,用来共同组成一个完整对象的。
持久层Hibernate聚合实现
在持久层我们需要做的主要工作就是将上述Domain Model 进行持久化映射配置,以User为例,User是一个实体,我们配置User.hbm.xml如下:
〈hibernate-mapping〉
〈class name="sample.model.User" table="testuser"〉
〈id name="userId" type="java.lang.String" 〉
〈generator class="assigned"/〉
〈/id〉
〈property name="username" type="java.lang.String"〉
〈column name="name" /〉
〈/property〉
〈!--表示和部门Dept之间是一种多对一关系 --〉
〈many-to-one cascade="save-update" name="dept"
class="sample.model.Dept" column="categoryId" /〉
〈!-- 表示和用户属性UserPropperty之间是一种1对多关系--〉
〈bag name="userProps" inverse="true" cascade="all" 〉
〈key column="userId" /〉
〈one-to-many class="sample.model.UserProperty" /〉
〈/bag〉
〈/class〉
〈/hibernate-mapping〉
在User的映射配置文件中,我们很自然地表达了上节Model之间的聚合关系,通过Hibernate配置,我们将模型对象之间的关系可以持久化保存到数据库中了,也就是可以永久维持这种关系,实际上,现实世界中也是这样的,部分和整体的关系是一直存在,除非这个整体这个对象不存在,而且修改部分对象内部值,必须通过整体这个对象。
在user配置中,我们并没有去做任何关系数据表testuser的设计和设定,因为我们知道,当User.hbm.xml配置完成后,这个J2EE系统部署发布到J2EE容器中时,Hibernate会根据这个配置自动创建数据表testuser,数据表的建立已经是一个部署调试阶段的、技术层面的具体工作。
Hibernate重要的父子关系
Hibernate在处理User和UserProperty这样一对多的父子关系时,具体实现起来要有一些具体细节必须注意,而且Hibernate2和Hibernate3两个版本是不一样的:
当我们需要只通过一句话session.save(user)或session.update(user)就能完成User和它其中多个Userproperty都能自动保存或更新时(必须指定cascade="all" 或save-update),尤其是update(user)更新时,其子集合userProps属性中可能有一些Userproperty是修改过的,一些Userproperty则是新增的,对于新增要使用insert语句;而对于修改则使用update语句,当我们笼统地调用一句update(user)时,那么Hibernate是如何判断这个user中子集合中哪些是修改?哪些是新增的?
Hibernate是通过主键来判断的,也就是说,通过UserProperty的主键来判断该对象是修改?还是新增。最关键的是:这个主键必须由Hibernate自动产生,如果你想自己指定子对象UserProperty主键,那么就有可能很多麻烦,这个麻烦是出其的麻烦,无法判断具体原因。所以,在简单方便的道路上迈错一步就是万丈深渊。下面是UserProperty的映射配置:
〈hibernate-mapping〉
〈class name="sample.model.UserProperty" table="userprops"〉
〈id name="propId" type="java.lang.String" 〉
〈generator class="uuid.hex"/〉〈!-- 不能为assigned--〉
〈/id〉
〈property name="name" /〉
〈property name="value" /〉
〈!-- 为提升性能而设定 --〉
〈many-to-one name="user" column="userId" not-null="true"/〉
〈/class〉
〈/hibernate-mapping〉
注意:以上配置只适合Hibernate 3.0以上版本,如果是Hibernate 2,那么必须在 :
〈id name="propId" type="java.lang.String" 〉
中加入unsaved-value="null",而且这个值是null还是0或-1,取决你的主键类型:
〈id name="propId" type="java.lang.String" unsaved-value="null"〉
是不是感觉Hibernate2太麻烦了!在Hibernate3中,就没有这个规定了,所以,如果当初使用Hibernate2来实现J2EE的oo简洁实现之道,还存在技术上的困难和难点。
Hibernate2和Hibernate3在处理父子关系上,还有一个不同就是lazy设定上:Hibernat2缺省lazy是false,当通过load将User获取以后,在session关闭以后,你可以直接通过user.getUserProps()方法获得其中子集合;而Hibernate3则不行了,缺省lazy是true,在session关闭情况下,只有两种方式获得子集合:
1. Open session in view,也就是在表现层一直打开持久层的session,这不但违背分层不干扰原则,而且造成数据库连接一直打开,一旦出错,有可能造成内存泄漏死机等问题。
2.在load父对象User时,调用Hibernate.initialize(user.getUserProps());强行装载所有的子对象,这样问题是:我们再也无法通过简单一句load生成父对象User及其所有内部部分,而无须照顾其内部关系。
板桥实践中总结方法是:根据当初EJB CMP的读取模式,采取JDBC来读取整个User及其部分子集合,缺点也是必须在Dao语句中打开User(破坏封装),根据其内部结构从数据库中获取数据,这样的好处是:我们可以使用统一的Hibernate模板来进行任何一个模型的持久化(不必为每个模型写一套DAO实现类),而无须关心其内部结构了。
注意:Spring+Hibernate采取的是Open session in view方案,这也是这种架构在系统复杂时发生性能问题一个原因,J道性能板块有多个这样的求救贴。
使用Hibernate映射配置另外一个注意点就是:使用双向关系可以提高性能,但是Evans DDD告诉我们,建模时尽量搞 单向关系,不要用双向,这两者有矛盾之处,实际中,我们如果使用Hibernate作为持久层框架,那么就采取双向,性能很重要啊,否则后果很严重,这种设计和性能不匹配也是目前面向对象领域需要解决的另外一个问题。
通过在子对象UserPropery配置中引入many-to-one ,然后在父对象User配置中规定inverse="true" 来实现双向,Hibernate会通过和insert或update一条SQL语句完成关系设定。
表现层Struts聚合实现
前面我们完成了Hibernate的映射配置,下面是表现层的映射配置,这是使用标签库来实现,我们使用Struts的标签库来实现:在界面主要实现下图效果:
当进行用户User资料增删改查时,需要一个如图录入页面,部门是通过下来菜单选择,用户属性UserPropery是通过一行行属性名称和属性值输入的,主要是在user.jsp中完成:
〈html:form action="/userSaveAction.do" method='post'〉
〈html:hidden property="action" /〉
〈!-- 下拉菜单选择部门,通过使用Struts的Action串联,产生deptListForm新ActionForm--〉
〈html:select property="dept.deptId" 〉
〈logic:notEmpty name="deptListForm" 〉
〈html:optionsCollection name="deptListForm" property="list" value="deptId" label="name"/〉
〈/logic:notEmpty〉
〈/html:select〉
〈br〉
UserId:〈html:text property="userId" /〉
〈br〉
Username:〈html:text property="username" /〉
〈table〉
〈tr〉〈td〉属性Id〈/td〉〈td〉属性名称〈/td〉〈td〉属性值〈/td〉〈/tr〉
〈tr〉〈td〉
〈html:hidden property="userProp[0].propId" /〉
〈/td〉〈td〉
〈html:text property="userProp[0].name" /〉
〈/td〉〈td〉
〈html:text property="userProp[0].value" /〉
〈/td〉〈/tr〉
〈tr〉〈td〉
〈html:hidden property="userProp[1].propId" /〉
〈/td〉〈td〉
〈html:text property="userProp[1].name" /〉
〈/td〉〈td〉
〈html:text property="userProp[1].value" /〉
〈/td〉〈/tr〉
〈tr〉〈td〉
〈html:hidden property="userProp[2].propId" /〉
〈/td〉〈td〉
〈html:text property="userProp[2].name" /〉
〈/td〉〈td〉
〈html:text property="userProp[2].value" /〉
〈/td〉〈/tr〉
〈/table〉
〈br〉〈input type='submit' value='submit'〉〈/input〉
〈/html:form〉
相应的UserActionForm和User Model内容差不多,不同之处:为接受多个动态属性的输入,需要设定一个特定的方法:
public class UserForm extends ModelForm {
.....
public UserProperty getUserProp(int index) {
return (UserProperty)((List)userProps).get(index);
}
.....
}
增删改查和批量查询根据JdonFramework的简化可迅速配置实现,这里不再描述,整个项目的代码结果如下图:也就是10个类左右,而且都是和业务有关,简要,扣主题,整个案例代码是免费自由下载,作为JdonFramework应用源码下载之一的sample。
总结
一个真正面向对象的JavaEE或J2EE系统,应该是一个围绕领域模型的多层架构,以面向对象OO思维进行领域模型提炼和重构,继续以OO思维进行表现层和持久层的配置实现,才能寻找到一条Java系统快速有效高质量的解决之道。
http://www.jdon.com/artichect/javaee.html
yanglilibaobao收录,使用标签:项目管理,时间:2007-8-6 16:42:07 | 相关网摘,我也收藏
北京外企人力资源服务有限公司(FESCO)最新调查统计显示,今年上半年外企职位日语软件开发等冷门专业的中高端人才短缺,而初级秘书、助理、会计、人力资源等大众行业人才需求仍然很旺,占外企人才市场需求的62%。
随着北京外包业经济发展规划的力度加大以及相应政策的调整,IT外包已经成为北京的朝阳产业,一些外资公司纷纷在京建立IT的外包基地或发展外包产业,测试工程师、日语软件工程师、程序员等职位出现较大的人才需求潜力。其中,比较突出的人才短缺出现在专业软件开发。
中低端职位需求仍然是目前活跃在整个外企人才招聘市场的主力职位,初级秘书、助理、会计等大众行业需求占整体市场需求的62%;市场、销售类人才占11%;日语专业需求占7.4%;IT/通讯类占7%;工业类占5.4%。
http://tech.sina.com.cn/it/2007-08-06/08301658051.shtml
yanglilibaobao收录,使用标签:.NET,时间:2007-8-6 16:41:05 | 相关网摘,我也收藏
分部方法的语法
在看C#语言的What's New时,突然发现新特性列表的最后,多出了一个“Partial Method Definitions ”,但并不像其他新特性一样有超链接链接到其说明。上网搜索了一下,关于分部类型的信息非常少。尤其是中文信息,只有CSDN的 周融 在其《C# 3.5 语言在 Visual Studio Orcas Beta 1 上的新增功能(二) 》一文的最后提到了这个分部方法,但没有进一步说明。英文技术文章中,倒是有两篇不错的:http: //blogs.msdn.com/wesdyer/archive/2007/05/23/in-case-you-haven-t-heard.aspx 和 http://community.bartdesmet.net/blogs/bart/archive/2007/07/28/c-3-0-partial -methods-what-why-and-how.aspx.
又仔细看了一下MSDN Library for Visual Studio 2008 Beta 2,终于对这个语言特性有所了解,在这里介绍一下,希望对大家有所帮助。
分部方法的定义和分部类型类似,只需在方法定义前添加partial关键字。但分部方法只能拆分成两个部分——一部分是定义声明(Definition Declaration),另一部分是实现声明(Implement Declaration)。其中定义声明看上去和抽象方法类似:
partial class CA
{
// ……
private void partial M(); // 定义声明|
而实现声明看上去和普通方法类似:
private void partial M() // 实现声明
{
// 方法体
}
在调用分部方法时,和调用其他方法一样:
CA a = new CA();
a.M();
只是,如果只有定义声明而没有编写实现声明,则编译器不会发射(Emit)该方法和调用该方法的语句的元数据与IL代码。换言之,如果没有编写实现声明,则编译得到的程序集中,CA类型里并没有M这个方法。
使用分部方法的注意事项
分部方法的语法非常简单,但有一些事项要注意。
如果没有写实现声明,则不会发射方法调用代码,也不会对参数进行求值。因此,对于下面的例子:
class CA { partial void M(int i); static void Main() { CA a = new CA(); int i = 0; a.M(i++); } }
分部方法M只有定义声明,没有实现声明,因此也不会发射调用该方法的代码:a.M(i++),因此也不会对i++进行求值。所以最终i的值依然是0.但如果为M编写了实现声明,则a.M(i++)的代码会被编译到最终的程序集中,同时参数也被求值,i的值将被变为1.
分部方法只能出现在分部类中。
分部方法必须是私有(private)的,并且返回值类型必须是void.
分部方法可以带有参数,并且其参数可以带有this、params和ref修饰符,但不能带有out修饰符。
分部方法不可以是虚拟(virtual)的。
分部方法不可以是外部(extern)的。
分部方法可以是静态(static)的,也可以是不安全(unsafe)的。
分部方法可以是泛型方法,泛型约束必须放置在定义声明中,但也可以在事先声明中重复说明。在定义声明和实现声明中,类型参数和类型参数的名字不一定必须一致。
不能将分部方法封装到一个委托中。
分部方法的应用场景
分部方法和分部类型的初衷是类似的,一方面可以使得不同的开发者能够同时编写一个类型的不同部分,另一方面可以分离自动生成的代码和用户手写的代码。和分部类型一样,分部方法也会在编译初期被合并成一个方法定义。猜测:从微软的角度来看,第二个“初衷”可能才是真正的初衷。
由此,分部方法有如下几个应用场景:(场景1 出自In Case You Haven't Heard这篇文章「http://blogs.msdn.com/wesdyer/archive/2007/05/23/in-case-you- haven-t-heard.aspx」),场景2 出自Visual Studio 2008的Linq to SQL技术,而场景3 则是Anders Liu自已臆想出来的。
场景1 轻量级事件处理
有的时候,自动生成的代码需要事件这类语言构造来通知用户对某些操作进行处理,但实际上用于编写的代码就位于自动生成的类型之中。此时,或者需要触发一个事件,或者就需要生成一个virtual方法来让用户继承。但无论是事件还是继承,开销都是比较大的,所以可以通过分部方法来实现轻量级的处理方式。如下面的类:(本例子引用自前述的In Case You Haven't Heard一文)
partial class Customer { string name; public string Name { get { return name; } set { OnBeforeUpdateName(); OnUpdateName(); name = value; OnAfterUpdateName(); } } partial void OnBeforeUpdateName(); partial void OnAfterUpdateName(); partial void OnUpdateName(); }
这里定义了三个分部方法,其意义不言而喻。假设这是系统自动生成的代码,则我们只需在另外一个源代码文件中的partial class Customer中实现这几个分部方法即可。
场景2 自定义DataContext中的Insert、Update、Delete方法
当使用Linq to SQL向项目中加入了实体类之后,还会创建一个XxxDataContext类,这个类继承自DataContext类,并且是partial的。这个类封装了具体的数据库操作功能(实体类仅封装数据库中的数据),如对象的插入、更新和删除等。
下面我们来看一下这个自动生成的类定义:
[System.Data.Linq.Mapping.DatabaseAttribute(Name="AdventureWorks")] public partial class AdventureWorksDataContext : System.Data.Linq.DataContext { private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource(); #region Extensibility Method Definitions partial void OnCreated(); partial void InsertAWBuildVersion(AWBuildVersion instance); partial void UpdateAWBuildVersion(AWBuildVersion instance); partial void DeleteAWBuildVersion(AWBuildVersion instance); ......
这里我们可以看到一系列的partial方法。其中第一个OnCreated实际上属于场景1中描述的情况,是一个轻量级的事件,表示 DataContext环境对象创建完毕。而其他partial方法则用于自定义DataContext的IUD操作。对于每一个表(实体类),这里都会出现一组InsertXxx、UpdateXxx和DeleteXxx方法。如果我们希望自定义删除行为(如希望将一个IsDelete字段设置为 true来表示已删除),则可以在另一个文件中扩展这个partial类,并为对应的Delete方法提供实现声明。
场景3 新的调试信息输出方法
这是Anders Liu臆想的场景,在分部方法的协助下,我们可以写出这样的代码:
partial class CA { partial void DebugPrint(string msg); ... void F() { .... DebugPrint("aaa"); } } partial class CA { #if DEBUG partial void DebugPrint(string msg); { Debug.WriteLine(msg); } #endif }
这样做的好处在于,我们还是反过来说罢,如果不这样做,必须在每次调用调试代码时都加入#if判断。而这样可以将调试代码都写成方法,在一处用#if进行判断。
缺点在于,由于分部方法必须是私有的,所以必须针对每个类写一套调试代码。
小结
嗯,总而言之,Anders Liu在这篇文章里说的是分部方法。
http://dotnet.chinaitlab.com/CSharp/727264.html
yanglilibaobao收录,使用标签:软件测试,时间:2007-8-6 16:18:06 | 相关网摘,我也收藏
人是测试工作中最有价值也是最重要的资源,没有一个合格的、积极的测试小组,测试就不可能实现。然而,在软件开发产业中有一种非常普遍习惯,那就是让那些经验最少的新手、没有效率的开发者或不适合干其他工作的人去做测试工作。这绝对是一种目光短浅的行为,对一个系统进行有效的测试所需要的技能绝对不比进行软件开发需要的少,事实上,测试者将获得极其广泛的经验,他们将遇到许多开发者不可能遇到的问题。
①、沟通能力
一名理想的测试者必须能够同测试涉及到的所有人进行沟通,具有与技术(开发者)和非技术人员(客户,管理人员)的交流能力。既要可以和用户谈得来,又能同开发人员说得上话,不幸的是这两类人没有共同语言。和用户谈话的重点必须放在系统可以正确地处理什么和不可以处理什么上。而和开发者谈相同的信息时,就必须将这些活重新组织以另一种方式表达出来,测试小组的成员必须能够同等地同用户和开发者沟通。
②、移情能力
和系统开发有关的所有人员都处在一种既关心又担心的状态之中。用户担心将来使用一个不符合自己要求的系统,开发者则担心由于系统要求不正确而使他不得不重新开发整个系统,管理部门则担心这个系统突然崩溃而使它的声誉受损。测试者必须和每一类人打交道,因此需要测试小组的成员对他们每个人都具有足够的理解和同情,具备了这种能力可以将测试人员与相关人员之间的冲突和对抗减少到最低程度。
③、技术能力
就总体言,开发人员对那些不懂技术的人持一种轻视的态度。一旦测试小组的某个成员作出了一个错误的断定,那么他们的可信度就会立刻被传扬了出去。一个测试者必须既明白被测软件系统的概念又要会使用工程中的那些工具。要做到这一点需要有几年以上的编程经验,前期的开发经验可以帮助对软件开发过程有较深入的理解,从开发人员的角度正确的评价测试者,简化自动测试工具编程的学习曲线。
④、自信心
开发者指责测试者出了错是常有的事,测试者必须对自己的观点有足够的自信心。如果容许别人对自己指东指西,就不能完成什么更多的事情了。
⑤、外交能力
当你告诉某人他出了错时,就必须使用一些外交方法。机智老练和外交手法有助于维护与开发人员的协作关系,测试者在告诉开发者他的软件有错误时,也同样需要一定的外交手腕。如果采取的方法过于强硬,对测试者来说,在以后和开发部门的合作方面就相当于“赢了战争却输了战役”。
⑥、幽默感
在遇到狡辩的情况下,一个幽默的批评将是很有帮助的。
⑦、很强的记忆力
一个理想的测试者应该有能力将以前曾经遇到过的类似的错误从记忆深处挖掘出来,这一能力在测试过程中的价值是无法衡量的。因为许多新出现的问题和我们已经发现的问题相差无几。
⑧、耐心
一些质量保证工作需要难以置信的耐心。有时你需要花费惊人的时间去分离、识别和分派一个错误。这个工作是那些坐不住的人无法完成的。
⑨、怀疑精神
可以预料,开发者会尽他们最大的努力将所有的错误解释过去。测式者必须听每个人的说明,但他必须保持怀疑直到他自己看过以后。
⑩、自我督促
干测试工作很容易使你变得懒散。只有那些具有自我督促能力的人才能够使自己每天正常地工作。
11、洞察力
一个好的测试工程师具有“测试是为了破坏”的观点,捕获用户观点的能力,强烈的质量追求,对细节的关注能力。应用的高风险区的判断能力以便将有限的测试针对重点环节。
http://softtest.chinaitlab.com/Manage/727448.html
yanglilibaobao收录,使用标签:软件测试,时间:2007-8-6 16:14:54 | 相关网摘,我也收藏
人们常常以为,开发一个程序是困难的,测试一个程序则比较容易。这其实是误解。设计测试用例是一项细致并需要高度技巧的工作,稍有不慎就会顾此失彼,发生不应有的疏漏。
不论是黑盒测试方法还是白盒测试方法,由于测试情况数量巨大,都不可能进行彻底的测试。所谓彻底测试,就是让被测程序在一切可能的输入情况下全部执行一遍。通常也称这种测试为“穷举测试”。 “黑盒”法是穷举输入测试,只有把所有可能的输入都作为测试情况使用,才能以这种方法查出程序中所有的错误。实际上测试情况有无穷多个,人们不仅要测试所有合法的输入,而且还要对那些不合法但是可能的输入进行测试。 “白盒”法是穷举路径测试,贯穿程序的独立路径数是天文数字,但即使每条路径都测试了仍然可能有错误。第一,穷举路径测试决不能查出程序违反了设计规范,即程序本身是个错误的程序。第二,穷举路径测试不可能查出程序中因遗漏路径而出错。第三,穷举路径测试可能发现不了一些与数据相关的错误。E.W.Dijkstra的一句名言对测试的不彻底性作了很好的注解:“程序测试只能证明错误的存在,但不能证明错误不存在”。
在实际测试中,穷举测试工作量太大,实践上行不通,这就注定了一切实际测试都是不彻底的。当然就不能够保证被测试程序中不存在遗留的错误。软件工程的总目标是充分利用有限的人力和物力资源,高效率、高质量地完成测试。为了降低测试成本,选择测试用例时应注意遵守“经济性”的原则。第一,要根据程序的重要性和一旦发生故障将造成的损失来确定它的测试等级;第二,要认真研究测试策略,以便能使用尽可能少的测试用例,发现尽可能多的程序错误。掌握好测试量是至关重要的,一位有经验的软件开发管理人员在谈到软件测试时曾这样说过:“不充分的测试是愚蠢的,而过度的测试是一种罪孽”。测试不足意味着让用户承担隐藏错误带来的危险,过度测试则会浪费许多宝贵的资源。
测试是软件生存期中费用消耗最大的环节。测试费用除了测试的直接消耗外,还包括其它的相关费用。能够决定需要做多少次测试的主要影响因素如下:
①、系统的目的
系统的目的的差别在很大程度上影响所需要进行的测试的数量。那些可能产生严重后果的系统必须要进行更多的测试。一台在Boeing 757上的系统应该比一个用于公共图书馆中检索资料的系统需要更多的测试。一个用来控制密封燃气管道的系统应该比一个与有毒爆炸物品无关的系统有更高的可信度。一个安全关键软件的开发组比一个游戏软件开发组要有苛刻得多的查找错误方面的要求。
②、潜在的用户数量
一个系统的潜在用户数量也在很大程度上影响了测试必要性的程度。这主要是由于用户团体在经济方面的影响。一个在全世界范围内有几千个用户的系统肯定比一个只在办公室中运行的有两三个用户的系统需要更多的测试。如果不能使用的话,前一个系统的经济影响肯定比后一个系统大。除此而外,在分配处理错误的时候,所花的代价的差别也很大。如果在内部系统中发现了一个严重的错误,在处理错误的时候的费用就相对少一些,如果要处理一个遍布全世界的错误就需要花费相当大的财力和精力。
③、信息的价值
在考虑测试的必要性时,还需要将系统中所包含的信息的价值考虑在内,一个支持许多家大银行或众多证券交易所的客户机/服务器系统中含有经济价值非常高的内容。很显然这一系统需要比一个支持鞋店的系统要进行更多的测试。这两个系统的用户都希望得到高质量、无错误的系统,但是前一种系统的影响比后一种要大得多。因此我们应该从经济方面考虑,投入与经济价值相对应的时间和金钱去进行测试。
④、开发机构
一个没有标准和缺少经验的开发机构很可能开发出充满错误的系统。在一个建立了标准和有很多经验的开发机构中开发出来的系统中的错误不会很多,因此,对于不同的开发机构来说,所需要的测试的必要性也就截然的不同。 然而,那些需要进行大幅度改善的机构反而不大可能认识到自身的弱点。那些需要更加严格的测试过程的机构往往是最不可能进行这一活动的,在许多情况下,机构的管理部门并不能真正地理解开发一个高质量的系统的好处。
⑤、测试的时机
测试量会随时间的推移发生改变。在一个竟争很激烈的市场里,争取时间可能是制胜的关键,开始可能不会在测试上花多少时间,但几年后如果市场分配格局已经建立起来了,那么产品的质量就变得更重要了,测试量就要加大。测试量应该针对合适的目标进行调整。
http://softtest.chinaitlab.com/Manage/727451.html
yanglilibaobao收录,使用标签:软件测试,时间:2007-8-6 16:11:55 | 相关网摘,我也收藏
白盒测试作为测试人员常用的一种测试方法,越来越受到测试工程师的重视。白盒测试并不是简单的按照代码设计用例,而是需要根据不同的测试需求,结合不同的测试对象,使用适合的方法进行测试。因为对于不同复杂度的代码逻辑,可以衍生出许多种执行路径,只有适当的测试方法,才能帮助我们从代码的迷雾森林中找到正确的方向。本文介绍六种白盒子测试方法:语句覆盖、判定覆盖、条件覆盖、判定条件覆盖、条件组合覆盖、路径覆盖。
白盒测试的概述
由于逻辑错误和不正确假设与一条程序路径被运行的可能性成反比。由于我们经常相信某逻辑路径不可能被执行, 而事实上,它可能在正常的情况下被执行。由于代码中的笔误是随机且无法杜绝的,因此我们要进行白盒测试。
白盒测试又称结构测试,透明盒测试、逻辑驱动测试或基于代码的测试。白盒测试是一种测试用例设计方法,盒子指的是被测试的软件,白盒指的是盒子是可视的,你清楚盒子内部的东西以及里面是如何运作的。
白盒的测试用例需要做到:
·保证一个模块中的所有独立路径至少 被使用一次
·对所有逻辑值均需测试 true 和 false
·在上下边界及可操作范围内运行所有循环
·检查内部数据结构以确保其有效性
白盒测试的目的:通过检查软件内部的逻辑结构,对软件中的逻辑路径进行覆盖测试;在程序不同地方设立检查点,检查程序的状态,以确定实际运行状态与预期状态是否一致。
白盒测试的特点:依据软件设计说明书进行测试、对程序内部细节的严密检验、针对特定条件设计测试用例、对软件的逻辑路径进行覆盖测试。
白盒测试的实施步骤:
1.测试计划阶段:根据需求说明书,制定测试进度。
2.测试设计阶段:依据程序设计说明书,按照一定规范化的方法进行软件结构划分和设计测试用例。
3.测试执行阶段:输入测试用例,得到测试结果。
4.测试总结阶段:对比测试的结果和代码的预期结果,分析错误原因,找到并解决错误。
白盒测试的方法:总体上分为静态方法和动态方法两大类。
静态分析是一种不通过执行程序而进行测试的技术。静态分析的关键功能是检查软件的表示和描述是否一致,没有冲突或者没有歧义。
动态分析的主要特点是当软件系统在模拟的或真实的环境中执行之前、之中和之后 , 对软件系统行为的分析。动态分析包含了程序在受控的环境下使用特定的期望结果进行正式的运行。它显示了一个系统在检查状态下是正确还是不正确。在动态分析技术中,最重要的技术是路径和分支测试。下面要介绍的六种覆盖测试方法属于动态分析方法。
白盒测试的优缺点
1. 优点
·迫使测试人员去仔细思考软件的实现
·可以检测代码中的每条分支和路径
·揭示隐藏在代码中的错误
·对代码的测试比较彻底
·最优化
2. 缺点
·昂贵
·无法检测代码中遗漏的路径和数据敏感性错误
·不验证规格的正确性
六种覆盖方法
首先为了下文的举例描述方便,这里先给出一张程序流程图。(本文以1995年软件设计师考试的一道考试题目为例,图中红色字母代表程序执行路径)。
1、语句覆盖
1)主要特点:语句覆盖是最起码的结构覆盖要求,语句覆盖要求设计足够多的测试用例,使得程序中每条语句至少被执行一次。
2)用例设计:(如果此时将A路径上的语句1—〉T去掉,那么用例如下)
X Y 路径
1 50 50 OBDE
2 90 70 OBCE
3)优点:可以很直观地从源代码得到测试用例,无须细分每条判定表达式。
4)缺点:由于这种测试方法仅仅针对程序逻辑中显式存在的语句,但对于隐藏的条件和可能到达的隐式逻辑分支,是无法测试的。在本例中去掉了语句1—〉T去掉,那么就少了一条测试路径。在if结构中若源代码没有给出else后面的执行分支,那么语句覆盖测试就不会考虑这种情况。但是我们不能排除这种以外的分支不会被执行,而往往这种错误会经常出现。再如,在Do-While结构中,语句覆盖执行其中某一个条件分支。那么显然,语句覆盖对于多分支的逻辑运算是无法全面反映的,它只在乎运行一次,而不考虑其他情况。
2、判定覆盖
1)主要特点:判定覆盖又称为分支覆盖,它要求设计足够多的测试用例,使得程序中每个判定至少有一次为真值,有一次为假值,即:程序中的每个分支至少执行一次。每个判断的取真、取假至少执行一次。
2)用例设计:
X Y 路径
1 90 90 OAE
2 50 50 OBDE
3 90 70 OBCE
3)优点:判定覆盖比语句覆盖要多几乎一倍的测试路径,当然也就具有比语句覆盖更强的测试能力。同样判定覆盖也具有和语句覆盖一样的简单性,无须细分每个判定就可以得到测试用例。
4)缺点:往往大部分的判定语句是由多个逻辑条件组合而成(如,判定语句中包含AND、OR、CASE),若仅仅判断其整个最终结果,而忽略每个条件的取值情况,必然会遗漏部分测试路径。
3、条件覆盖
1)主要特点:条件覆盖要求设计足够多的测试用例,使得判定中的每个条件获得各种可能的结果,即每个条件至少有一次为真值,有一次为假值。
2)用例设计:
X Y 路径
1 90 70 OBC
2 40 OBD
3)优点:显然条件覆盖比判定覆盖,增加了对符合判定情况的测试,增加了测试路径。
4)缺点:要达到条件覆盖,需要足够多的测试用例,但条件覆盖并不能保证判定覆盖。条件覆盖只能保证每个条件至少有一次为真,而不考虑所有的判定结果。
4、判定/条件覆盖
1)主要特点:设计足够多的测试用例,使得判定中每个条件的所有可能结果至少出现一次,每个判定本身所有可能结果也至少出现一次。
2)用例设计:
X Y 路径
1 90 90 OAE
2 50 50 OBDE
3 90 70 OBCE
4 70 90 OBCE
3)优点:判定/条件覆盖满足判定覆盖准则和条件覆盖准则,弥补了二者的不足。
4)缺点:判定/条件覆盖准则的缺点是未考虑条件的组合情况。
5、组合覆盖
1)主要特点:要求设计足够多的测试用例,使得每个判定中条件结果的所有可能组合至少出现一次。
2)用例设计:
X Y 路径
1 90 90 OAE
2 90 70 OBCE
3 90 30 OBDE
4 70 90 OBCE
5 30 90 OBDE
6 70 70 OBDE
7 50 50 OBDE
3)优点:多重条件覆盖准则满足判定覆盖、条件覆盖和判定/条件覆盖准则。更改的判定/条件覆盖要求设计足够多的测试用例,使得判定中每个条件的所有可能结果至少出现一次,每个判定本身的所有可能结果也至少出现一次。并且每个条件都显示能单独影响判定结果。
4)缺点:线性地增加了测试用例的数量。
6、路径覆盖
1)主要特点:设计足够的测试用例,覆盖程序中所有可能的路径。
2)用例设计:
X Y 路径
1 90 90 OAE
2 50 50 OBDE
3 90 70 OBCE
4 70 90 OBCE
3)优点:这种测试方法可以对程序进行彻底的测试,比前面五种的覆盖面都广。
4)缺点:由于路径覆盖需要对所有可能的路径进行测试(包括循环、条件组合、分支选择等),那么需要设计大量、复杂的测试用例,使得工作量呈指数级增长。而在有些情况下,一些执行路径是不可能被执行的,如:
If (!A)B++;
If (!A)D--;
这两个语句实际只包括了2条执行路径,即A为真或假时候对B和D的处理,真或假不可能都存在,而路径覆盖测试则认为是包含了真与假的4条执行路径。这样不仅降低了测试效率,而且大量的测试结果的累积,也为排错带来麻烦。
总结
白盒测试是一种被广泛使用的逻辑测试方法,是由程序内部逻辑驱动的一种单元测试方法。只有对程序内部十分了解才能进行适度有效的白盒测试。但是贯穿在程序内部的逻辑存在着不确定性和无穷性,尤其对于大规模复杂软件。因此我们不能穷举所有的逻辑路径,即使穷举也未必会带来好运(穷举不能查出程序逻辑规则错误,不能查出数据相关错误,不能查出程序遗漏的路径)。
那么正确使用白盒测试,就要先从代码分析入手,根据不同的代码逻辑规则、语句执行情况,选用适合的覆盖方法。任何一个高效的测试用例,都是针对具体测试场景的。逻辑测试不是片面的测试正确的结果或是测试错误的结果,而是尽可能全面地覆盖每一个逻辑路径。
http://softtest.chinaitlab.com/tool/727465.html
yanglilibaobao收录,使用标签:软件测试,时间:2007-8-6 16:08:51 | 相关网摘,我也收藏
测试实践对于每个行业、每个公司、每个测试人员都是不一样的。但是大多数的测试项目在某些要素上是有共同之处的。让我们把那些有共性的要素称之为“普通测试”吧。在我们的经验中,普通测试包括根据某种规格说明书写一些测试用例。这些测试用例是松散地指导测试人员去测试一个产品的零散的计划或者过程。然后测试人员按照预期的那样在整个产品中执行那些测试用例,重复地,在项目过程中从头到尾地执行。
快速测试与传统测试主要有以下几方面的区别:
1. 首先,不浪费时间。最快速的行动是完全不行动。因此,在快速测试中,我们要消灭掉任何不必要的活动。比较起来,传统测试是比较臃肿的,随之也带来一定的混乱。当然,需要通过一些培训和经验来知道如何来对传统测试“瘦身”。一般地说,流线型的文档(应该是指大量的文档)和虔诚的测试是最容易发生风险的区域。不要因为别人告诉你重复是好的,你就来回的测同一个东西。确保你从每个测试中得到了好的、有价值的信息。要考虑每次测试活动的机会成本2.Mission.在快速测试中我们不是以Task为导向(如写测试用例),我们是以Mission为导向的。我们的目标可能是“快点找到重要的问题”。如果是这样,那么写测试用例可能不是最好的方式。另一方面,如果我们的目标是“使FDA听众满意”,那么我们不仅要写测试用例,还要按照指定的规格来写某几种测试用例。理解我们的Mission,然后估算一下我们的形势,并找到我们能朝着实现该目标立即开始执行的最快、最有用的行动。
3.技巧。做好任何的测试都要求技巧。普通测试不重视测试技巧的重要性,它更多关注测试文档的格式而不是测试的健壮性。快速测试,就像我们描述的,强调测试技巧。它不是像用微波炉炸爆米花那样的机械技术,或者是在DMV(机动车管理部门)填表格。健壮的测试是非常重要的,因此我们练习批判性思维和试验设计技巧。一个测试新手不会在测试中做得很好,除非有一个在测试艺术、技艺上有较高造诣的资深测试人员来监督和指导。我们希望本站点的一些文章能够在这些技巧上帮助你。
4.风险。普通测试关注功能和结构上的产品覆盖率。换句话说,如果产品能做什么,就测什么。快速测试更关注重要的问题。基于对产品的理解,找出那些我们认为的最可能发生并且发生后影响较大的问题。然后投入我们的主要精力来测试那些问题。快速测试往往意味着尽可能快的揭露最重要的信息。
5.探索。快速测试也是快速学习,因此我们使用探索性测试。我们避免先写测试用例,除非有明确和强制性的要求。我们更喜欢让上一个测试影响我们的下一个测试。这是一个好事情,因为我们并没有被预先设计好的测试步骤所禁锢,而且让我们发现了更好的测试思想。让测试快速地执行的其它方式,例如很多的测试自动化,总是有着这样的风险――即使运行了大量的非常快速的测试也不能在产品中帮助你找到重要的问题。
6.启发法。我们必须当心高估所测试的问题,因此我们使用启发法(简单的翻译成:拇指规则)来帮助我们避免思维短路,并且更快地测试。启发法本质上是反应――在某种意义上有偏差地反应――通常是帮助我们在正确地时间测试正确的东西。快速测试收集、记住并且练习使用有帮助的启发法。在普通测试中,启发法也有被使用,但是测试人员往往并不知道自己使用了这个方法,也不能完全地掌控这个方法。
7.团队合作。快速测试意味着作弊。至少,我们做的事情在以前小学老师的眼中就是作弊:我们尽可能事先弄清楚事情,我们借用其它人的工作,我们使用我们能找到的任何资源和工具。例如,快速测试的一个重要的技术就是成对测试:两个人,一台电脑。这个思想在XP(极限编程)的实践中被证明是有效的,并且在测试工作中也很适用。在普通测试的经验中,测试人员通常安静、独自的工作,而不是像一群迅捷的狼在捕猎bugs. 8.反省。我们的快速测试人员应该要经常问我们正在做什么和为什么这样做。我们要解析我们自己,并且讨论更好的测试策略和状况。
http://softtest.chinaitlab.com/skills/727467.html
yanglilibaobao收录,使用标签:软件测试,时间:2007-8-6 16:01:02 | 相关网摘,我也收藏
解析测试工程师职业发展瓶颈
经过这几年的发展,国内IT公司的测试水平有了很大的提高,但是与此同时,很多测试工程师也迎来了个人的发展瓶颈:很多人从测试工程师做到了测试经理的职位,不知道下一步如何发展;或者每天机械地从事着功能测试工作。
本文首先从分析测试工程师的发展现状和职业化过程遇到的问题入手;接着分析什么样的测试人员才是合格的;最后介绍测试人员的职业历程以及如何突破自己的职业发展瓶颈。
1 测试工程师帖子解析
下面是在一些测试网站上收集的帖子,主要是一些测试工程师介绍自己的成长历程或者对测试行业的看法。从这些帖子中,我们可以看出测试工程师职业发展遇到的一些问题。
帖子一:踏实地发展自己
我在北京工作有4年了。职业发展依次经历了测试员-测试工程师-测试分析师-测试经理。这就是我在北京的4年测试生涯。个人对测试工作有如下的观点:
1)软件测试不像一些人看起来那么简单,需要相当深厚的技术背景。但只要掌握要领,也不像我们一些人所认为的那么困难;
2)测试工程师和开发人员相比,可以有机会接触更多的、不同行业的项目,是一个大的优势。
3)测试工程师要想成功,更多的是靠平时的积累。不管是项目的积累,还是平时学习,两者都至关重要。
4)测试工程师要充分利用网络资源,与同行们充分交流,在互相帮助和学习的氛围中,可以加快自己成长速度。
点评:这是一位比较踏实的测试工程师,一步一个胶印地走着自己的测试之路,我们可以认为他是相对成功的典范。现实中我们很多测试工程师不是抱怨工资低,就是抱怨自己公司的测试环境不好。如果要想在测试领域走向成功,重要的秘诀就是踏踏实实地学习,认认真真地做好本职工作。
帖子二:执着的测试工程师
我做测试工作快6年了。刚开始的时候,我是公司的第一个测试员,虽然公司也在做ISO9000,但是什么规范都得自己摸索。可是,我仍然坚持下来了,而且大有收获,虽然在公司里不受重视。
但是随着测试工作的不断深入,自己对公司的主流业务(我们作的是行业软件)从外行变成了内行。而且还发现了一些产品的设计方面的欠缺,在老板和开发主管面前树立了自己的一些威信。至少在一些项目进行需求分析的时候,会来征求我的意见。而且,目前做到了不经测试的产品不给客户。当然,在我和开发经理发生分歧的时候,大部分时间老板还是支持开发经理,但我认为是正确的地方还是会据理力争的。
一句话,测试人员是孤独的,寂寞的。但只要坚持,总能有收获的,尤其是在发现了隐藏很深的一些BUG的时候,那种成就感和自豪感真的是一种很好的感觉。
实际上,做任何一行工作,都会遇到不公平。但为什么要去跟别人比呢,只要自己有提高,就是好的。
点评:“敢做冷板凳的人”才是勇敢的人,这位发帖子的测试工程师不但有勇气坐了冷板凳,而且能够坚持下来,直到取得了不错的成绩。“实际上,做任何一行工作,都会遇到不公平。但为什么要去跟别人比呢,只要自己有提高,就是好的。”几句朴实无华的话说出了如何做好测试工作的真谛。
测试人员一定要给自己正确的定位,既然选择了目前地位有些低的测试工作,就应该踏实的做好,这是走向成功的必由之路。
帖子三:好学而有信心的新手
我在一家外企作了一段时间的兼职测试,之前我从未接触过测试。开始的时候只作一些Manual test,后来就开始做Automated test,修改原有的test cases,或者重写一些test cases。然后test小组的leader建议我写测试文档,他说写文档有利于一个tester技术水平的提高。因为你必须要熟悉软件项目的整体框架,洞悉软件深层的结构才能写出高质量的测试用例。
于是,我在网上查了一些关于测试方面的资料,发现测试真的很重要。对一个软件项目而言,老外对软件测试尤其重视。我兼职的这个外企是有一半的员工是测试的,大概有7、8个人。个人认为,国内的软件企业对测试的重视程度还不够,但是毋庸置疑,测试是软件企业产品线上和开发同等重要的。可以预言,未来的国内软件行业,软件测试人员可能会占据软件团队半数左右。同时,对测试人员的能力要求也是比较高的。
综上,我觉得Software test很有前途。当然,这些都是一个测试新手的看法,可能比较片面,全当给大家打打气了。
点评:可以看出这是一位很有远见的测试工程师。现实中很多测试工程师是由于不能从事其它工作才从事测试的,因而工作中也是不断地抱怨待遇、团队环境等不能满足自己的要求。在此建议测试工程师,如果选择了这个行业,就应该认真地对待工作,抱怨永远解决不了问题。只有像这位测试工程师一样认真分析自己的行业,才可以有更好的职业化发展,否则还不如换一个自己喜欢的工作去试一试。
帖子四:郁闷而犹豫的测试工程师
我做软件测试也有两年多的时间了,但是在这两年中似乎没有太多的提高。因为都是黑盒测试,所以一般就是使用产品,最多也就是一些工具测试。可是这都是想到哪就测到哪,也没有真正按照测试文档执行。公司测的东西组合情况也很多,根本没办法。而且公司测试流程也不规范。
刚开始没签约的时候,还是专职测试,签了以后简直就变成打杂的了。什么都要做,连一些设计文档都推了过来,有时候还要去现场了解客户需求,真是非常佩服老板把一个人当三个人用的能力。总的感觉在小公司里,根本就没有测试员这个概念,测试员一般什么都得做。当你提出一堆建议的时候,老板总是会说,现在公司规模还不具备条件,以后会慢慢的改善的,可我感觉过两年公司可能已经倒闭了。
真是有点郁闷,改行做开发,又不想放弃这个被很看好的职业。可是光被看好又怎么样呢?说不定十几年前,扫大街的就像现在的做测试的。都是做质量保证,扫大街的要保证城市环境的质量,现在呢?他们又怎么样?
点评:其实测试和开发一样,都不是那么想当然的理想,国内开发环境也和测试一样混乱。而开发人员发展到高级程序员就会成为很多人的发展瓶颈,薪资和职务都很难再提升。而测试与开发相比的一个巨大优势在于它是一个新兴的领域,拥有更多的机会,测试人员工作三五年,再有一些管理经验,很容易做到测试主管,虽然薪资待遇相对低些,但是给个人的长期发展打好了基础。看准了就应该去做,实实在在的学到知识才是最重要的。
2 国内软件测试测试工程师职业发展现状
我们可以从两个方面来解析测试测试工程师的职业瓶颈问题:
l 从企业方面:多数企业较难招聘到满意的测试工程师,尤其在软件测试外包企业,人才问题成了这类企业的发展瓶颈,这些恰恰反映了整个测试行业的发展遇到了瓶颈;
l 从个人方面:很多测试人员薪资和职位到了一定阶段就很难得到提升,例如很多测试工程师做到测试经理后,几年内得不到提升。
职业发展尤其体现在待遇方面。下表是北京市一些IT企业测试工程师的月薪数据。这些数据主要从一些网站收集,由一些测试工程师发布。
职称名
税前月薪(人民币:元)
备注
少于100人
100~200人
200人以上
初级工程师
1500~2000
2000~2500
3000~4000
手工执行功能测试,这些人通常是一年以内工作经验的新手。
2000~3000
2500~3500
一年到两年经验的测试工程师,工作内容通常以功能测试为主。
中级工程师
2500~3500
3000~4000
2500~3500
编写并执行测试用例,通常工作两年以上。
3500~4000
4000~4500
3500~4500
编写并执行测试用例,能够使用一些测试工具。通常工作两年以上。
高级工程师
4000~5000
5000~6000
6000~7000
熟练使用测试工具,制定测试计划,编写并执行测试用例等。工作经验通常三年以上。
7000~8000
能编写自动化测试脚本与进行白盒测试工作。具有一定的开发技能。工作经验通常三年以上。
测试分析师
4000~5000
5000~6000
6000~7000
具有一定分析能力的高级测试工程师。工作经验通常四年以上。
6000~7000
7000~8000
能够设计测试方案,执行测试并对测试结果进行全面的分析,例如性能测试分析。
测试组长
4000~5000
6000~7000
6000~7000
带领10人以内的测试小组执行测试任务。
5000~6000
http://www.testing.ac.cn/html/18/0/516/1.htm
yanglilibaobao收录,使用标签:项目管理,时间:2007-8-6 15:51:27 | 相关网摘,我也收藏
伴随软件行业的发展,业界公司也不断对软件的研发开发模式进行了深入的探讨,形成目前业界比较流程的几个软件开发模式,例如MSF、RUP、XP、CMM,而这些模式都存在相应的优势和缺点;同时因为软件的类型多样、面向的客户对象不同、甚至使用的开发语言不同,决定了软件企业需要结合本公司的产品实际情况选择合适的开发模式;选择不当的开发模式会使软件的开发和测试陷入不断修改代码和测试软件的困境,增加了软件开发成本,延长了软件发布时间。
一、MSF模式
MSF于1994年首次引入,当时还是一个来自微软的产品开发过程中的一些最佳方法的松散集合,MSF产生后在微软产品组、交付中心、技术组和微软合作伙伴,甚至客户那里得到成功实施,并不断完善,既然MSF被众多软件企业所借鉴使用,MSF本身具备一些值得我们学习借鉴的优点,同时也存在一些需要注意,并进行适当改进的地方,接下来我们重点从组织、流程模型进行分析。
1.1、MSF小组模型
MSF 小组模型定义了小组同级成员的一些角色和职责,这些成员都在以相互依存的跨学科角色进行信息技术项目工作。下面的图表对该模型的逻辑进行了描述。
一个成功的软件项目需要同时实现多个目标,例如至少需要包含能够满足客户的要求、客户满意度要比较高;公司的投入要在一定范围内,要实现投资收益,毕竟商业企业的盈利是应该首要考虑的内容;项目的实际开发进行要受控不能无限拖延;最终的交付要有比较高的质量;整体软件系统的架构设计要比较合理、易于扩展、易于维护;同时还要求项目同时需要给公司带来新的技术积累、经验教训,从而使后续项目能够持续成功;而这些目标需要通过不同的活动来实现,软件项目的活动又具体划分为多种类型,大概主要划分为面向市场类活动、项目管理类活动、架构设计类活动、开发实现类活动、测试类活动、支撑类活动(例如配置管理等),而这些活动需要具备不同技能人员来执行,所以MSF具体定义了如下五类角色群:产品管理、程序管理、开发、测试、发布管理、用户体验,并且明确定义了五类角色具体职责,这些职责的定义对具体软件企业有很大的借鉴价值:
针对MSF小组模型定义,作者感觉重点体现如下优点:
1)按照角色群的方式定义,便于角色的分层管理;
2)角色、职责定义全面含盖了软件项目的所有必须的活动;
3)定义了根据不同项目情况,小组模式的扩展与收缩方法,对不同规模、不同类型的项目有很大的借鉴价值;
4)角色定义就体现了商业软件开发的市场驱动、财务驱动;
5)角色定义的层次体现了对测试、服务等职能工作的重视;
结合中国软件企业的管理现状,MSF在中国软件企业具体使用时就会暴露如下缺陷:
1)项目的责任主体不明确,缺少一个角色对项目的整体负责,产品管理对项目前端和后端负责、程序管理对项目中间负责,另MSF更强调的是大家协同共同为项目负责,甚至不同阶段项目的第一责任主体可以不同,体现了类似“生产模式”的研发。
2)MSF只定义了操作级项目模式,而没有详细定义项目决策团队的模式,在中国职能管理根深底厚,简单定义项目操作级的组织模式,项目实际执行中会因为人员来自不同职能部门产生比较多的冲突和相互配合问题。
1.2、流程模型
每个项目都要经过一个生命周期,这是一个包含项目里所有活动的过程,而这些活动的发生要到项目结束并过渡到操作状态才会结束。生命周期模型的主要功能是建立活动进行的顺序。正确的生命周期模型能够简化项目,并帮助确保每一个步骤都会让项目更加接近成功。下面是 MSF 过程模型生命周期的一个简图。
MSF 过程模型把来自传统的瀑布模型和螺旋模型的概念结合起来,以阶段和里程碑为基础,每个阶段都有其自身的特色,每个阶段的结束都代表了项目进展和中心点的变化。里程碑是检查和同步点,用来确定阶段的目标是否已经实现。同时MSF基于软件项目需求的特点(模糊性、易变性),建议采用版本化项目开发模式,具体就会出现多个版本的叠代开发,类似如下流程模型:
整体来讲MSF的流程模型定义是非常清晰的,也体现了软件项目的实际特征,作者感觉MSF流程模型集中体现了以下优点:
1)阶段化,将流程划分为明显的几个阶段,并且明确定义了阶段结束标准;
2)并行化,MSF流程模型把并行开发的思维体现的比较清晰,例如明确定义开发阶段就需要明确定义下阶段(稳定阶段)的集中测试所需要的测试用例;
3)阶段里程碑和内部小里程碑都被比较确切地定义,通过内部里程碑的控制可以有效控制项目构件的交付质量,通过阶段里程碑的控制可以有效解决构件之间的遗留问题,确保项目整体质量;
4)实现各个职能领域的交叉协同,流程模型中同时详细定义各个支撑角色(例如配置管理)的活动,实现了工程活动和管理活动的有效配合,从而从流程体系上保证了进度、质量、成本在一定范围的协调一致;
结合中国软件企业的管理现状,发现具体采用MSF流程模式进行实际项目开发时,也暴露出MSF需要具体补充和完善的地方,如下:
1)MSF流程模型是基于项目资源是有限的,而实际情况是一个公司往往同时会进行多个项目,MSF流程模式中没有对多项目管理进行详细描述,没有充分体现管道管理的思想,没有将管道管理贯彻在具体的项目流程模型中;
2)MSF流程模型中,缺少对公司高层管理团队活动职责的定义,更多局限在项目操作级,而实际情况是很多问题是在项目级无法解决的,所以如果没有明确定义高层的规范参与的话,无疑是增加了项目的风险;
整体来讲MSF是一个非常具有借鉴价值的软件开发模式,通过对MSF的分析研究,对实际公司研发体系的构建会有比较大的借鉴价值,后续我们会结合中国软件企业的实际情况,连续对RUP、CMM、XP、NPD-CMM等软件开发模式进行分析,敬请大家关注。
http://se.csai.cn/SPI/200707112058091237.htm