coverage 浏览器缓存怎么清理理缓存

对于游戏软件产品来说,这些需要特别注意重点控制的点关键,要求测试团队必需要加强以下几个方面,性能测试,代码的融合、相关性影响面的判断、版本的变更与控制,还有游戏性的分析与测试。性能测试主要加强以下几点,则需要注意在并发下服务器的稳定性监控,、网络流量与游戏客户端在大场面下的表现。;而版本控制在游戏软件的过程中,其意义更多——则会避免已经改了的问题重复出现,或是改了更新上去问题还是存在,如何高效的合并代码,、合成游戏资源、图片与角本脚本还是一个比较难度很高的事情,尤其涉及到多个部门。;而游戏性测试主要是避免那种些与游戏风格相背的情况,或是开发团队累死累活拼命完成得功能性任务做出的功能没有可延续性。
性能测试与版本控制,在大多数软件的测试流程中都会涉及,但是在不同的软件产品/项目中都有其特点。一般属于通用软件测试流程的部分,但而游戏性测试则需要对游戏感觉很好有比较深刻的了解,并由真正懂懂得的玩家的人来担任,。某些时候,他甚至可以不是一个很好的软件测试人员,但他一定是一个真正懂游戏的人,这里有一些扯远,但这里,本文稍后一节,将我会在后面会强调人的因素也决定了流程的实施。
下图是游戏迭代开发模型图
如果你去做电子商务,或是做门户,这些项目的适时性,高性能,复杂的功能会给你更高的技术要求,更高强的时间性效率挑战,对测试的设计,、执行,、与性能测试提出更高的要求。其实在大多数互联网公司经常会出现这样的情况:刚出去的功能又撤下来修改,或是性能达不到要求仍需要又要调优。许多一些人都会犯这样一个错,认为测试的时间不够,就只要测试执行,而忽略了其他几个环节就可以了,不做细致的分析与设计,为后续工作带来很大压力。其实,一个充分测试过的有质量保证的产品,可以减轻客服,、市场,、等各方面很多的压力。产品在用户和研发之间,反复,几次不如晚一些上提供给用户。从另外一方面看,这还需要测试主管能顶住某些压力。时间紧迫当然这不是理由,如何在流程上保证测试的需求分析,、用例的设计与研发在开发时同步进行是最重要的,这时你要加强早期的测试介入,明确卡住需求确认这一部分,。这样,在研发进入开发阶段时,测试团队也能进入测试设计,。当研发开发完成时,你测试团队事实上已经其本基本上完成了大部分的测试设计,并准备进入测试执行,。不要在开发提交后再去想如何测测试,抱怨之声也就不绝于耳了。这样才可能测试好一个时间比较紧的项目不管在用于测试的时间上,还是测试的质量上都无法满足要求。
,同时测试设计的很好,不仅可以节约测试执行的时间,也可以在反复提交的过程中,由于用例执行的一致性,保证了测试在多次的执行中的质量,;。同时也有发布的标准,一是缺陷的情况,二是用例的执行与覆盖。同时由于研发给的测试时间比较紧,所以有两件事情就必需作做好,:一是明确产品提交测试时间,并在研发延迟时给自己争取时间;二是在质量达不到要求的情况下,时间及时的做出反应,不要到最后在研发不了解项目质量的情况下建议研发延迟项目。为了达到上面的要求你必需要一个很好的测试平台,把设计,测试用例管理,执行与用例的联动,缺陷管理与报表统计打通,尽可能的利用平台解决事务性工作,降低流程执行的成本,。也就是说,既让测试人员可以集中精力去测试,同时又能够让研发管理人员随时获取正在进行测试的进度与质量,。当这些工作做到透明化时以后,就算让研发延迟发布,研发部门也会接收接受,。下图是这一阶段的大致流程
在这里可以跟大家说一下,我就曾经在产品发布权限不在测试这里部门的情况下,成功的让研发决定推迟发布了大约一半以上的项目,。大多数的测试部门主管,很难顶住来自项目/技术经理的压力是有理由的,因为他们根本不了解你做了哪些工作。有时候一些情况下,看似不可能的事情任务要想做成完成,关键要看在于事情的技巧,。流程表示了只是一个大方向的东西,而且,你永远也无法将责任推卸给流程也许是对的,更多情况下,作为测试主管,需要但将做事的方法与风格可以影响到推广到测试流程的推广中。
在测试互联网项目时,还有一个更重要的就是如何保证性能,。
也许大家会说不就是性能测试并不是单独存在的。其实不是完全正确,如果有充足的优秀高手人力资源做性能测试当然很好,但性能测试也不能完全保证所有的项目完全没有性能问题都完美无缺,因此,项目投入期间,同时性能测试是一个这个费时费力的工作,所以往往都是一般在资源不足的情况下开展的。作为测试主管,更应该,要学会判断那些相对更加重要的问题项目影响面会更广,需要集中做性能测试。这时你也许会问,那么会有人问其它相对不太重要的项目与问题怎么办,?其实做过性能调优的人都知道,大部分的性能问题都是由于一两个弱智的SQL语句导致的,所以可以从流程上加强对SQL查询语句在I/O问题的跟踪与评审,,从而避免大部分性能问题。
上面分析了不同公司根据上文的分析,不同类型的产品在测试流程上的是有很大差异的。这时,也许大家你也许可以把握测试流程大的方向了,但真正是否适合现有的测试团队与研发团队,则仍需要精心的调整,。当我遇到问题的时候,第一时间往往有时候不是去寻找流程不对的问题,而是通过现有资源与执行的方法可能需要着手来微调一下你的测试流程,直到发现问题的所在,并纪录下来,最后整合到原来设定的流程中。
这样的情况大概常常发生:比如说在需求上的处理,可能会有很多的测试人员会经常指责需求人员撰写的文档非常粗糙不详细,无法进行测试,。好像在我的记忆中,需求人员常常就是被骂的得灰头土脸,但是经过这些年在测试岗位上的工作,我才渐渐发现,其实有时候需求人员更需要鼓励鼓励是比职责更加有效的工作方式。这可能是一个放之四海皆准的工作态度。,指责只能加深对立,。其实在验收需求时,由于当时大家也只是知道一个大概我们的需求人员也只能从大致上把握核了解,可能大多数情况下是:原则上没有问题就通过了,。但然而,这种不负责任的态度却是给我们在做的测试工作带来相当多的麻烦。也只有在这样的时候,这些问题才能真正暴露出来,从而使测试设计时就会发现很多问题并没有写清楚,。一般情况下,很多测试人员这时就多半会放弃手边的工作,并消极地认为认为无法做工作无法继续下去。,等东西出来,并将问题最终归结到是需求给的不详细,而大加指责。
从我对测试主管工作的记事以来,就在印象中保留了这样的一幕。记的刚进一家公司时,我团队中的人员就开始经常会有下属跟我说抱怨,公司的需求工程师让我们太失望了。需求如何如何不好,然而,多少有些经验的我,当时我是把几家国内我服务过的顶尖公司情况作了一个简单的对比,的需求跟公司的需求人员的需求做了比较这时才发现,发现,原来我们公司的需求人员还是做的得不错的,。让测试人员把心态调整过来是测试主管的另外一件事。试问,,如果是你做需求作为需求工程师,是否会比他们做的好吗得更好??有了这样的基调,就可以让然后建议测试人员去总结不清楚的地方,给需求人员一个相对比较具体和明确的意见,这样顺利的了解了需求。
其实有时候不是流程不对流程在这其中并没有太多值得指责的地方,而是相互的理解与支持,换位思考而对流程的执行态度,却是更加关键的。我们不得不学会如何换位思考,并更多地从他人的角度来看待这些问题。
同样的问题还出现在还有需求变更上,很多测试人过不了这一关,。总是他们指责研发人员,让研发那些本来就已经恼火的软件工程师更加火冒三丈。换位思考一番,其实不难了解,,其实需求变更对研发工程师来说是更大的麻烦,。他们需要修改设计,、代码,相较而测试只要需改测试用例,他们的工作确实更加麻烦。简单来说,就ok了,其实大家要分析什么样的需求变更最可怕,而不是眉毛胡子一把抓,其实测试对需求变更并不可怕,怕的是只有在提交时才发现,导致测试时间不够,才会真正让测试人员心慌。这时需要从研发流程上保证变更及时的通知到测试就可以了行,。也许有人会说你也需要说:,说的倒很容易,如果研发不按照你的要求做怎么办!其实这里你只要用我所采用的方法是用数据说话,在项目进行时统计发生过多少次这样的事情,让研发管理层知道,让项目组之间有一个比较,。一方面,如果是一家公司重视质量的公司,必然会引起重视;另一方面,从质量管理部门角度本身出发,也应该推动公司重视质量。,随着时间的增加,需求变更给测试人员的反馈一定会有下降的趋势,。关键是测试不能抓住鸡毛就一直揪着不放宽容一些来看待身边的同事,要允许别人他们犯错,对于解决问题本身来说会大有裨益。只要趋势是好的就可以了。同时如果出现这样的情况并且极大影响到了测试进度,则要与研发部门沟通清楚,,如果研发不认可的情况下还可以请上级进行评估一下。
上面说的是不同态度在同样流程下的实现不同结果,下面主要讲一下关于自身资源是否胜任做流程上规定的事情,某些工作,也许并不一定是测试部门的优势,而另外一些,则需要根据测试团队的基本能力和资源进行评估。比如像性能测试、SQL的trace、自动化功能测试、单元测试集成、游戏性测试。其实这些流程上的关键点,可能大多数从功能测试上来一路走来的测试人员是无法做的到,这时要善于利用资源,不一定要测试做,可以从通过流程上保正有人来做积极调动其它部门的同事。,或是找有能力的人来做,测试可以进行监控。其实这种技术含量高一点的测试,对人的因素要求更大高,可以借助研发团队一起来做会有更好的效果,。记的第一次做Oracle数据库性能监控时,就是请的Oracle的DBA专家帮助设计了性能参数,成功的地进行了关于Oracle应用的性能测试。现在国内的测试人员普遍的技术水平不高,严重的v如果你对开发很精通,、同时又精通对测试颇有研究,、善于诊断性能与架构上的问题,、经常会帮助研发部门解决一些他们无法解决的事情,、同时又还懂的如何做测试管理,并了解研发人员的心态,那就真得的找不出你还有不成功的理由了任何理由让人不对你刮目相看了。
作者:蒲冬梅&&& 文章来源:CSDN&&&
最近读Cem Kaner,James Bach,Bret Pettichord合著的《软件测试经验与教训》受益颇多,因此根据文中的部份内容总结出来与大家共享,希望能达到知识交流与共享的目的。如果感兴趣,也可以阅读原书。
测试报告是产品部与技术部进行沟通的主要手段,测试报告的好坏直接影响BUG的修改速度和程序员的心情。如果下苦功夫研究并写好报告,则所有阅读这些报告的人都会受益。因此我整理并撰写此文,希望对于能修直产品部与技术部的桥梁有所帮助。
一、 缺陷报告的原则
1、 有些错误永远也不会改正。测试员的责任不是保证所有错误都得到改正,而是准确报告问题,使程序员能够理解问题的影响。而深入研究并写出好的报告,常常对错误改正的可能性产生巨大的影响。
2、 及时报告缺陷。不要等到第二天或是下周才报告程序错误,不要等到忘记了一些关键细节才报告。拖延的时间越长,程序错误被解决的可能性就越小。
3、 每个程序错误都需要单独报告。不要努力把不同的程序错误合并到同一份报告,来减轻项目经理或程序员对重复错误报告的不断抱怨。如果多个程序错误写到一份报告中,有些错误就可能得不到修改。
4、 小缺陷也值得报告。小错误会使客户感到困惑,并降低客户对产品其他部份的信心。被认为是很小的缺陷可能包括拼写错误、小的屏幕格式问题,鼠标遗迹、小的计算错误,图形比例不准、在线帮助错误、不适当的灰掉了的菜单选项、不起作用的快捷键、不正确的错误信息,以及其它程序员认为不值得花精力去修改的缺陷。
5、 努力使错误报告有更高的价值。由于有很多人都要阅读并依赖错误报告,因此要下功夫丰富每个错误报告的信息。提高报告的可理解性。如:A、清楚列出错误报告的前置条件与实现的每一个步骤,避免前后语言混乱,它应该只需要描述现象,不要在产生错误的步骤中试图给出程序员的解决办法。这样会使错误报告看来冗长而难于理解。如果有好的解决办法或建议可以附在错误报告描述之后。B、要始终保持中立语气。C、不要开玩笑,否则有可能造成误解。
6、 永远都要报告不可重现的错误,这样的错误可能是时间炸弹。不可重现的错误可能会是公司能够支付的最昂贵的缺陷。有时错误无法重现。看到程序错误一次,但不知道如何使其再次出现。如果产品交付客户还出现这种情况,会影响客户对产品的信心,如果技术支持人员需要很长时间评估客户的数据或环境,客户则会更加厌烦。如果测试员清晰地报告错误征兆,程序员通过研究测试员怎么得到特定消息,或当测试员查看对话框或点击特定控件时可能会出现的情况。从而能够跟踪代码,相信程序员能够改正报告中“不可重现”缺陷中的20%。但在报告此类BUG时,一定要明确说明自己不能重现这个程序错误。
二、 缺陷报告的注意事项
1、 引用别人的错误报告要小心。如果没有得到错误报告的提交者的允许,可以补充评论,但不能编辑别人的材料。对于其他测试员的错误报告即使很糟糕也不要擅自修改。任何时候需要在错误报告中做补充,都要注明自己的姓名和日期。
2、 看似极端的缺陷可能是潜在的安全漏洞。如在一个在预期接受一个1~99的字段中,输入65536个9会导致程序崩溃。会有人真的这么干吗?是的,有人当然要这样做。有人会认为“如果有人愚蠢到这样做,程序崩溃会教训他“而忽略该错误,但实际上白痴不是惟一滥用程序的人。任何会产生严重后果的问题都应该解决,不管其多么“不可能”发生,当熟练的攻击者利用程序中的缺陷得手后,会写下这个消息并广为传播,使得其所有生手都可以使用脚本。
3、 立即对程序错误延迟决定上诉,如果决定据理力争,就一定要赢。如果测试员对某个BUG的处理有意见,确实需要上诉,不要依赖自己最初错误报告中的语言和信息,报告是不可更改的,但是测试员需要列举更有效的例子,测试员需要与其他产品项目相关人员沟通,补充做一些后续测试,寻找该程序错误可能存在的更严重的错误。程序员所做的每个上诉都必须是有说服力的。即使不能赢得所有上诉(当然不可能赢得所有上诉)也应该得到自己的所有上诉理应获胜的好名声。
至此,上面罗列的条款都与我们实际工作有着密切的关联,希望能借助此篇文章,让你能有兴趣读完本书的全部内容,相信一定能让你获益匪浅。
回复:如何写好测试报告 曾盛开(技术部)
我看完了,总是觉得程序员和测试员之间在问题分歧上存在很多不同之处,其中包括个人专业知识的深度,对软件理解的能力,对业务、程序的理解能力,产品开发成本、周期与bug之间的协调。
诸多方面加起来,使我的脾气在沟通协调bug问题上变得很容易激昂,或者说发火,头脑发热。程序员多少都有些自大,不甘屈服的情绪,而且确实很多东西由于变得和以前写好、定好的需求有出入,导致做好的东西可能又被推翻。。。心里那种滋味很不好受的。。。毕竟每个地方和环节都是自己努力去想过的,有时候一个问题可能是花去几天时间确保那样做没有漏洞和正确。
我感觉到两个部门之间协调缺少更多互动,比如产品部在测试之前或者有空时候可以培训一下技术部,一般会测试哪些东西,如何测试的,这样子程序员心里多少有更多的底,在写程序的时候会有一种警惕性,从而产品部也会轻松一些,双方有利,应该是三方有利,公司最有利。。产品部也要考虑如何帮助程序员快速有利地处理bug,而不是一味为了bug而找bug,这根本背离了两个部门合作的基调;技术部也同样有责任去帮助产品部理解好系统运行的流程,找出隐藏的bug 。
另外,我想说的是在文档细节上面不要过分苛求,否则一方面是开发进度和成本,另一方面是使Xp轻量级文档开发流程又变成重量级文档开发,程序员为了文档忙于疲命。。我深有体会的,文档花去的时间几乎占用了1/4-1/3。
我觉得在测试的同事面前谈测试,有些班门弄斧,关公卖刀,但有些话不得不说,那就开诚布公拿出来,就算贻笑大方也好吧~~~
回复:回复:如何写好测试报告 李鹏
文档花去的时间几乎占用了1/4-1/3:这个时间我不觉得多,我觉得不够。花在需求定义,开发文档方面的时间应该是1/2以上我觉得XP编程不适合我们,理由有三:1、我们的8.0项目跨度有近2年,可以说是个中型项目,xp编程比较适合小项目(2-3个月)。2、xp编程理论中基本上没有提到如何对程序进行系统的测试,而我们公司非常重视软件测试,程序员和测试员的比例近1:1。3、xp中对文档的定义是“够用就好”,而在众多的工程理论(rup、cmm)中都建议要有详尽得需求和开发文档。花在需求定义,开发文档方面的时间应该是1/2以上。
回复:回复:如何写好测试报告 黄为东
技术部和产品部的斗争性,有它的积极作用,但确实存在两个部门目标不一致性的问题,既存在内部损耗,又存在被共同忽视的中间地带。大胆设想一下,假设把技术部和产品部合并为一个大部,每个小组都配2个测试员,是否会更好呢?这样测试人员对本组开发人员的配合密切程度也许会更高。问题是,测试的专业性、分工性是否会下降?该怎么组织,是一个大问题。
回复:回复:如何写好测试报告 蒲冬梅
产品只有足够人性化,用户才会乐意使用此功能,而不是买回去就将其束之高阁。文档只有足够详细化,才能为产品部测试提供准确的依据。因此就需要产品部与技术部能够有更多沟通,更充分的文档准备,更大的耐心。
因为最终目标我们只有一个,做出来的产品要对得起用户。因此我们需要彼此体谅,理解与尊重。
如果技术部有时间或是计划能够安排接受产品部的测试培训,我想我们部门每个同事都会举双手双脚赞成的。这样应该能减少很大部份测试的工作量。
关于为了找BUG而找BUG的说法,我觉得是很有必要就此申明一两句的。现在产品部最终提交到技术部的BUG都是有人负责审核的(BUG的定位是否准确,BUG的描述是否清晰等)。由于BUG的数量,这项工作其实是相当费时与费力的,因此曾停过一段的时间,但是为了提高BUG的质量和减少为了BUG而需要与产品部沟通的时间,这部份工作我们依然坚持在做。但是难免会有部份BUG在产品部进行准确定位是很困难的,而如果改为由技术部来定位则仅仅只是几分钟的事情,因此我们并未严格控制每个BUG都会精确定位,但是我们的目标是尽可能减少技术部为了BUG的描述或定位而进行多次反复的沟通。
因此就BUG本身的问题,也欢迎技术部能多多提意见,我们一定坚绝改正。
近期因工作需要,希望比较全面的总结下SQL SERVER数据库性能优化相关的注意事项,在网上搜索了一下,发现很多文章,有的都列出了上百条,但是仔细看发现,有很多似是而非或者过时(可能对SQL SERVER6.5以前的版本或者ORACLE是适用的)的信息,只好自己根据以前的经验和测试结果进行总结了。
我始终认为,一个系统的性能的提高,不单单是试运行或者维护阶段的性能调优的任务,也不单单是开发阶段的事情,而是在整个软件生命周期都需要注意,进行有效工作才能达到的。所以我希望按照软件生命周期的不同阶段来总结数据库性能优化相关的注意事项。
一、分析阶段
一般来说,在系统分析阶段往往有太多需要关注的地方,系统各种功能性、可用性、可靠性、安全性需求往往吸引了我们大部分的注意力,但是,我们必须注意,性能是很重要的非功能性需求,必须根据系统的特点确定其实时性需求、响应时间的需求、硬件的配置等。最好能有各种需求的量化的指标。
另一方面,在分析阶段应该根据各种需求区分出系统的类型,大的方面,区分是OLTP(联机事务处理系统)和OLAP(联机分析处理系统)。
二、设计阶段
设计阶段可以说是以后系统性能的关键阶段,在这个阶段,有一个关系到以后几乎所有性能调优的过程—数据库设计。
在数据库设计完成后,可以进行初步的索引设计,好的索引设计可以指导编码阶段写出高效率的代码,为整个系统的性能打下良好的基础。
以下是性能要求设计阶段需要注意的:
1、 数据库逻辑设计的规范化
数据库逻辑设计的规范化就是我们一般所说的范式,我们可以这样来简单理解范式:
第1规范:没有重复的组或多值的列,这是数据库设计的最低要求。
第2规范: 每个非关键字段必须依赖于主关键字,不能依赖于一个组合式主关键字的某些组成部分。消除部分依赖,大部分情况下,数据库设计都应该达到第二范式。
第3规范: 一个非关键字段不能依赖于另一个非关键字段。消除传递依赖,达到第三范式应该是系统中大部分表的要求,除非一些特殊作用的表。
更高的范式要求这里就不再作介绍了,个人认为,如果全部达到第二范式,大部分达到第三范式,系统会产生较少的列和较多的表,因而减少了数据冗余,也利于性能的提高。
2、 合理的冗余
完全按照规范化设计的系统几乎是不可能的,除非系统特别的小,在规范化设计后,有计划地加入冗余是必要的。
冗余可以是冗余数据库、冗余表或者冗余字段,不同粒度的冗余可以起到不同的作用。
冗余可以是为了编程方便而增加,也可以是为了性能的提高而增加。从性能角度来说,冗余数据库可以分散数据库压力,冗余表可以分散数据量大的表的并发压力,也可以加快特殊查询的速度,冗余字段可以有效减少数据库表的连接,提高效率。
3、 主键的设计
主键是必要的,SQL SERVER的主键同时是一个唯一索引,而且在实际应用中,我们往往选择最小的键组合作为主键,所以主键往往适合作为表的聚集索引。聚集索引对查询的影响是比较大的,这个在下面索引的叙述。
在有多个键的表,主键的选择也比较重要,一般选择总的长度小的键,小的键的比较速度快,同时小的键可以使主键的B树结构的层次更少。
主键的选择还要注意组合主键的字段次序,对于组合主键来说,不同的字段次序的主键的性能差别可能会很大,一般应该选择重复率低、单独或者组合查询可能性大的字段放在前面。
4、 外键的设计
外键作为数据库对象,很多人认为麻烦而不用,实际上,外键在大部分情况下是很有用的,理由是:
外键是最高效的一致性维护方法,数据库的一致性要求,依次可以用外键、CHECK约束、规则约束、触发器、客户端程序,一般认为,离数据越近的方法效率越高。
谨慎使用级联删除和级联更新,级联删除和级联更新作为SQL SERVER 2000当年的新功能,在2005作了保留,应该有其可用之处。我这里说的谨慎,是因为级联删除和级联更新有些突破了传统的关于外键的定义,功能有点太过强大,使用前必须确定自己已经把握好其功能范围,否则,级联删除和级联更新可能让你的数据莫名其妙的被修改或者丢失。从性能看级联删除和级联更新是比其他方法更高效的方法。
5、 字段的设计
字段是数据库最基本的单位,其设计对性能的影响是很大的。需要注意如下:
A、数据类型尽量用数字型,数字型的比较比字符型的快很多。
B、 数据类型尽量小,这里的尽量小是指在满足可以预见的未来需求的前提下的。
C、 尽量不要允许NULL,除非必要,可以用NOT NULL+DEFAULT代替。
D、少用TEXT和IMAGE,二进制字段的读写是比较慢的,而且,读取的方法也不多,大部分情况下最好不用。
E、 自增字段要慎用,不利于数据迁移。
6、 数据库物理存储和环境的设计
在设计阶段,可以对数据库的物理存储、操作系统环境、网络环境进行必要的设计,使得我们的系统在将来能适应比较多的用户并发和比较大的数据量。
这里需要注意文件组的作用,适用文件组可以有效把I/O操作分散到不同的物理硬盘,提高并发能力。
7、 系统设计
整个系统的设计特别是系统结构设计对性能是有很大影响的,对于一般的OLTP系统,可以选择C/S结构、三层的C/S结构等,不同的系统结构其性能的关键也有所不同。
系统设计阶段应该归纳一些业务逻辑放在数据库编程实现,数据库编程包括数据库存储过程、触发器和函数。用数据库编程实现业务逻辑的好处是减少网络流量并可更充分利用数据库的预编译和缓存功能。
8、 索引的设计
在设计阶段,可以根据功能和性能的需求进行初步的索引设计,这里需要根据预计的数据量和查询来设计索引,可能与将来实际使用的时候会有所区别。
关于索引的选择,应改主意:
A、根据数据量决定哪些表需要增加索引,数据量小的可以只有主键。
B、根据使用频率决定哪些字段需要建立索引,选择经常作为连接条件、筛选条件、聚合查询、排序的字段作为索引的候选字段。
C、把经常一起出现的字段组合在一起,组成组合索引,组合索引的字段顺序与主键一样,也需要把最常用的字段放在前面,把重复率低的字段放在前面。
D、一个表不要加太多索引,因为索引影响插入和更新的速度。
三、编码阶段
编码阶段是本文的重点,因为在设计确定的情况下,编码的质量几乎决定了整个系统的质量。
编码阶段首先是需要所有程序员有性能意识,也就是在实现功能同时有考虑性能的思想,数据库是能进行集合运算的工具,我们应该尽量的利用这个工具,所谓集合运算实际是批量运算,就是尽量减少在客户端进行大数据量的循环操作,而用SQL语句或者存储过程代替。关于思想和意识,很难说得很清楚,需要在编程过程中来体会。
下面罗列一些编程阶段需要注意的事项:
1、 只返回需要的数据
返回数据到客户端至少需要数据库提取数据、网络传输数据、客户端接收数据以及客户端处理数据等环节,如果返回不需要的数据,就会增加服务器、网络和客户端的无效劳动,其害处是显而易见的,避免这类事件需要注意:
A、横向来看,不要写SELECT *的语句,而是选择你需要的字段。
B、纵向来看,合理写WHERE子句,不要写没有WHERE的SQL语句。
C、 注意SELECT INTO后的WHERE子句,因为SELECT INTO把数据插入到临时表,这个过程会锁定一些系统表,如果这个WHERE子句返回的数据过多或者速度太慢,会造成系统表长期锁定,诸塞其他进程。
D、对于聚合查询,可以用HAVING子句进一步限定返回的行。
2、尽量少做重复的工作
这一点和上一点的目的是一样的,就是尽量减少无效工作,但是这一点的侧重点在客户端程序,需要注意的如下:
A、控制同一语句的多次执行,特别是一些基础数据的多次执行是很多程序员很少注意的。
B、减少多次的数据转换,也许需要数据转换是设计的问题,但是减少次数是程序员可以做到的。
C、杜绝不必要的子查询和连接表,子查询在执行计划一般解释成外连接,多余的连接表带来额外的开销。
D、合并对同一表同一条件的多次UPDATE,比如
1.&UPDATE EMPLOYEE SET FNAME=’HAIWER’ WHERE EMP_ID=’ VPA30890F’
2.&UPDATE EMPLOYEE SET LNAME=’YANG’ WHERE EMP_ID=’ VPA30890F’&&&&&&&&
这两个语句应该合并成以下一个语句
1.&&&& UPDATE EMPLOYEE SET FNAME=’HAIWER’,LNAME=’YANG’&
2.&&&& WHERE EMP_ID=’ VPA30890F’
E、&UPDATE操作不要拆成DELETE操作+INSERT操作的形式,虽然功能相同,但是性能差别是很大的。
F、&不要写一些没有意义的查询,比如
&&& SELECT * FROM EMPLOYEE WHERE 1=2
3、 注意事务和锁
事务是数据库应用中和重要的工具,它有原子性、一致性、隔离性、持久性这四个属性,很多操作我们都需要利用事务来保证数据的正确性。在使用事务中我们需要做到尽量避免死锁、尽量减少阻塞。具体以下方面需要特别注意:
A、事务操作过程要尽量小,能拆分的事务要拆分开来。
B、 事务操作过程不应该有交互,因为交互等待的时候,事务并未结束,可能锁定了很多资源。
C、 事务操作过程要按同一顺序访问对象。
D、提高事务中每个语句的效率,利用索引和其他方法提高每个语句的效率可以有效地减少整个事务的执行时间。
E、 尽量不要指定锁类型和索引,SQL SERVER允许我们自己指定语句使用的锁类型和索引,但是一般情况下,SQL SERVER优化器选择的锁类型和索引是在当前数据量和查询条件下是最优的,我们指定的可能只是在目前情况下更有,但是数据量和数据分布在将来是会变化的。
F、 查询时可以用较低的隔离级别,特别是报表查询的时候,可以选择最低的隔离级别(未提交读)。
4、 注意临时表和表变量的用法
在复杂系统中,临时表和表变量很难避免,关于临时表和表变量的用法,需要注意:
A、如果语句很复杂,连接太多,可以考虑用临时表和表变量分步完成。
B、 如果需要多次用到一个大表的同一部分数据,考虑用临时表和表变量暂存这部分数据。
C、 如果需要综合多个表的数据,形成一个结果,可以考虑用临时表和表变量分步汇总这多个表的数据。
D、其他情况下,应该控制临时表和表变量的使用。
E、 关于临时表和表变量的选择,很多说法是表变量在内存,速度快,应该首选表变量,但是在实际使用中发现,这个选择主要考虑需要放在临时表的数据量,在数据量较多的情况下,临时表的速度反而更快。
F、 关于临时表产生使用SELECT INTO和CREATE TABLE + INSERT INTO的选择,我们做过测试,一般情况下,SELECT INTO会比CREATE TABLE + INSERT INTO的方法快很多,但是SELECT INTO会锁定TEMPDB的系统表SYSOBJECTS、SYSINDEXES、SYSCOLUMNS,在多用户并发环境下,容易阻塞其他进程,所以我的建议是,在并发系统中,尽量使用CREATE TABLE + INSERT INTO,而大数据量的单个语句使用中,使用SELECT INTO。
G、& 注意排序规则,用CREATE TABLE建立的临时表,如果不指定字段的排序规则,会选择TEMPDB的默认排序规则,而不是当前数据库的排序规则。如果当前数据库的排序规则和TEMPDB的排序规则不同,连接的时候就会出现排序规则的冲突错误。一般可以在CREATE TABLE建立临时表时指定字段的排序规则为DATABASE_DEFAULT来避免上述问题。
5、 子查询的用法
子查询是一个 SELECT 查询,它嵌套在 SELECT、INSERT、UPDATE、DELETE 语句或其它子查询中。任何允许使用表达式的地方都可以使用子查询。
子查询可以使我们的编程灵活多样,可以用来实现一些特殊的功能。但是在性能上,往往一个不合适的子查询用法会形成一个性能瓶颈。
如果子查询的条件中使用了其外层的表的字段,这种子查询就叫作相关子查询。相关子查询可以用IN、NOT IN、EXISTS、NOT EXISTS引入。
关于相关子查询,应该注意:
A、NOT IN、NOT EXISTS的相关子查询可以改用LEFT JOIN代替写法。比如:
1.&&&& SELECT PUB_NAME
2.&&&& FROM PUBLISHERS
3.&&&& WHERE PUB_ID NOT IN
4.&&&&&&& (SELECT PUB_ID
5.&&&&&&& FROM TITLES
6.&&&&&&& WHERE TYPE = 'BUSINESS')
&&&&&&&&&&& 可以改写成:
1.&&& SELECT A.PUB_NAME
2.&&& FROM PUBLISHERS A LEFT JOIN TITLES B
3.&&& ON&&&&&&& B.TYPE = 'BUSINESS' AND
4.&&&&&&&&&&&&& A.PUB_ID=B. PUB_ID
5.&&& WHERE B.PUB_ID IS NULL
1.&&&& SELECT TITLE
2.&&&& FROM TITLES
3.&&&& WHERE NOT EXISTS
4.&&&&&&& (SELECT TITLE_ID
5.&&&&&&& FROM SALES
6.&&&&&&& WHERE TITLE_ID = TITLES.TITLE_ID)
可以改写成:
1.&&&& SELECT TITLE
2.&&&& FROM TITLES LEFT JOIN SALES
3.&&&& ON SALES.TITLE_ID = TITLES.TITLE_ID
4.&&&& WHERE SALES.TITLE_ID IS NULL
B、 如果保证子查询没有重复 ,IN、EXISTS的相关子查询可以用INNER JOIN 代替。比如:
1.&&& SELECT PUB_NAME
2.&&& FROM PUBLISHERS
3.&&& WHERE PUB_ID IN
4.&&&&&& (SELECT PUB_ID
5.&&&&&& FROM TITLES
6.&&&&&& WHERE TYPE = 'BUSINESS')
可以改写成:
1.&&& SELECT DISTINCT A.PUB_NAME
2.&&& FROM PUBLISHERS A INNER JOIN TITLES B
3.&&& ON&&&&&&& B.TYPE = 'BUSINESS' AND
4.&&&&&&&&&&&&& A.PUB_ID=B. PUB_ID
C、 IN的相关子查询用EXISTS代替,比如
1.&&&& SELECT PUB_NAME
2.&&&& FROM PUBLISHERS
3.&&&& WHERE PUB_ID IN
4.&&&&&&& (SELECT PUB_ID
5.&&&&&&& FROM TITLES
6.&&&&&&& WHERE TYPE = 'BUSINESS')
可以用下面语句代替:
1.&&&& SELECT PUB_NAME
2.&&&& FROM PUBLISHERS
3.&&&& WHERE EXISTS
4.&&&&&&& (SELECT 1
5.&&&&&&& FROM TITLES
6.&&&&&&& WHERE TYPE = 'BUSINESS' AND
7.&&&&&&& PUB_ID= PUBLISHERS.PUB_ID)
D、不要用COUNT(*)的子查询判断是否存在记录,最好用LEFT JOIN或者EXISTS,比如有人写这样的语句:
1.&&&& SELECT JOB_DESC FROM JOBS
2.&&&& WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)=0
应该改成:
1.&&&& SELECT JOBS.JOB_DESC FROM JOBS LEFT JOIN EMPLOYEE&
2.&&&& ON EMPLOYEE.JOB_ID=JOBS.JOB_ID
3.&&&& WHERE EMPLOYEE.EMP_ID IS NULL
1.&&&& SELECT JOB_DESC FROM JOBS
2.&&&& WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)&&0
应该改成:
1.&&&& SELECT JOB_DESC FROM JOBS
2.&&&& WHERE EXISTS (SELECT 1 FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)
6、 慎用游标
数据库一般的操作是集合操作,也就是对由WHERE子句和选择列确定的结果集作集合操作,游标是提供的一个非集合操作的途径。一般情况下,游标实现的功能往往相当于客户端的一个循环实现的功能,所以,大部分情况下,我们把游标功能搬到客户端。
游标是把结果集放在服务器内存,并通过循环一条一条处理记录,对数据库资源(特别是内存和锁资源)的消耗是非常大的,所以,我们应该只有在没有其他方法的情况下才使用游标。
另外,我们可以用SQL SERVER的一些特性来代替游标,达到提高速度的目的。
A、字符串连接的例子
这是论坛经常有的例子,就是把一个表符合条件的记录的某个字符串字段连接成一个变量。比如需要把JOB_ID=10的EMPLOYEE的FNAME连接在一起,用逗号连接,可能最容易想到的是用游标:
3.&&&& DECLARENAME_CURSORCURSORFOR
4.&&&& SELECTFNAMEFROMEMPLOYEEWHEREJOB_ID=10ORDERBYEMP_ID
5.&&&& OPENNAME_CURSOR
8.&&&& BEGIN
12.& CLOSENAME_CURSOR
13.& DEALLOCATENAME_CURSOR
可以如下修改,功能相同:
1.&&&&&&& DECLARE @NAME VARCHAR(1000)
2.&&&&&&& SELECT @NAMES = ISNULL(@NAMES+’,’,’’)+FNAME
3.&&&&&&&&&& FROM EMPLOYEE WHERE JOB_ID=10 ORDER BY EMP_ID
B、 用CASE WHEN 实现转换的例子
很多使用游标的原因是因为有些处理需要根据记录的各种情况需要作不同的处理,实际上这种情况,我们可以用CASE WHEN语句进行必要的判断处理,而且CASE WHEN是可以嵌套的。比如:
1.&&&& CREATE TABLE 料件表(
2.&&&& 料号&&&&&&&&&& VARCHAR(30),
3.&&&& 名称&&&&&&&&&& VARCHAR(100),
4.&&&& 主单位&&&&&&&& VARCHAR(20),
5.&&&& 单位1&&&&&&&& VARCHAR(20),
6.&&&& 单位1参数&&&&& NUMERIC(18,4),
7.&&&& 单位2&&&&&&&& VARCHAR(20),
8.&&&& 单位2参数&&&&& NUMERIC(18,4)
13.& CREATE TABLE 入库表(
14.& 时间&&&&&&&&&&&&&& DATETIME,
15.& 料号&&&&&&&&&&&&&& VARCHAR(30),
16.& 单位&&&&&&&&&&&&&& INT,
17.& 入库数量&&&&&&&&&& NUMERIC(18,4),
18.& 损坏数量&&&&&&&&&& NUMERIC(18,4)
其中,单位字段可以是0,1,2,分别代表主单位、单位1、单位2,很多计算需要统一单位,统一单位可以用游标实现:
1.&&&& DECLARE @料号&&&& VARCHAR(30),
2.&&&&&&&&&&&& @单位&& INT,
3.&&&&&&&&&&&& @参数&&&&& NUMERIC(18,4),
5.&&&& DECLARE CUR CURSOR FOR
6.&&&&&&&&&&&& SELECT 料号,单位 FROM 入库表 WHERE 单位 &&0
7.&&&& OPEN CUR
8.&&&& FETCH NEXT FROM CUR INTO @料号,@单位
9.&&&& WHILE @@FETCH_STATUS&&-1
10.& BEGIN
11.&&& IF @单位=1
12.&&& BEGIN
13.&&&&& SET @参数=(SELECT 单位1参数 FROM 料件表 WHERE 料号 =@料号)
14.&&&&& UPDATE 入库表 SET 数量=数量*@参数,损坏数量=损坏数量*@参数,单位=1 WHERE CURRENT OF CUR
15.&&& END
16.&&& IF @单位=2
17.&&& BEGIN
18.&&&&& SET @参数=(SELECT 单位1参数 FROM 料件表 WHERE 料号 =@料号)
19.&&&&& UPDATE 入库表 SET 数量=数量*@参数,损坏数量=损坏数量*@参数,单位=1 WHERE CURRENT OF CUR
20.&&& END
21.&&& FETCH NEXT FROM CUR INTO @料号,@单位
23.& CLOSE CUR
24.& DEALLOCATE CUR
&&&&&&&&&& 可以改写成:
1.&&&& UPDATE A SET&
2.&&&& 数量=CASE A.单位 WHEN 1 THEN&&&&& A.数量*B. 单位1参数
3.&&&&&&&&&&&&&&&&&&&&&&& WHEN 2 THEN&&&&&&&& A.数量*B. 单位2参数
4.&&&&&&&&&&&&&&&&&&&&&&& ELSE A.数量
5.&&&& END,&&&&&&&&&&&&&&&&&&
6.&&&& 损坏数量= CASE A.单位 WHEN 1 THEN&&& A. 损坏数量*B. 单位1参数
7.&&&&&&&&&&&&&&&&&&&&&&& WHEN 2 THEN&&&&&&&& A. 损坏数量*B. 单位2参数
8.&&&&&&&&&&&&&&&&&&&&&&& ELSE A. 损坏数量
9.&&&& END,
10.& 单位=1&
11.& FROM入库表 A, 料件表 B
12.& WHERE&&& A.单位&&1&&&&& AND
13.&&&&&&&&&& A.料号=B.料号
C、 变量参与的UPDATE语句的例子
SQL ERVER的语句比较灵活,变量参与的UPDATE语句可以实现一些游标一样的功能,比如:
1.&&&& SELECT A,B,C,CAST(NULL AS INT) AS 序号
2.&&&& INTO #T
3.&&&& FROM 表
4.&&&& ORDER BY A ,NEWID()
产生临时表后,已经按照A字段排序,但是在A相同的情况下是乱序的,这时如果需要更改序号字段为按照A字段分组的记录序号,就只有游标和变量参与的UPDATE语句可以实现了,这个变量参与的UPDATE语句如下:
1.&&&& DECLARE @A INT
2.&&&& DECLARE @序号 INT
3.&&&& UPDATE #T SET
4.&&&&&&& @序号=CASE WHEN
THEN @序号+1 ELSE 1 END,
5.&&&&&&& @A=A,
6.&&&&&&& 序号=@序号
D、如果必须使用游标,注意选择游标的类型,如果只是循环取数据,那就应该用只进游标(选项FAST_FORWARD),一般只需要静态游标(选项STATIC)。
E、 注意动态游标的不确定性,动态游标查询的记录集数据如果被修改,会自动刷新游标,这样使得动态游标有了不确定性,因为在多用户环境下,如果其他进程或者本身更改了纪录,就可能刷新游标的记录集。
7、 尽量使用索引
建立索引后,并不是每个查询都会使用索引,在使用索引的情况下,索引的使用效率也会有很大的差别。只要我们在查询语句中没有强制指定索引,索引的选择和使用方法是SQLSERVER的优化器自动作的选择,而它选择的根据是查询语句的条件以及相关表的统计信息,这就要求我们在写SQL语句的时候尽量使得优化器可以使用索引。
为了使得优化器能高效使用索引,写语句的时候应该注意:
A、不要对索引字段进行运算,而要想办法做变换,比如
SELECT ID FROM T WHERE NUM/2=100
SELECT ID FROM T WHERE NUM=100*2
SELECT ID FROM T WHERE NUM/2=NUM1
如果NUM有索引应改为:
SELECT ID FROM T WHERE NUM=NUM1*2
如果NUM1有索引则不应该改。
发现过这样的语句:
1.&&&& SELECT 年,月,金额 FROM 结余表
2.&&&& WHERE 100*年+月=
应该改为:
1.&&&& SELECT 年,月,金额 FROM 结余表
2.&&&& WHERE 年=2007 AND
3.&&&&&&&&&& 月=10
B、 不要对索引字段进行格式转换
日期字段的例子:
WHERE CONVERT(VARCHAR(10), 日期字段,120)=’’
WHERE日期字段〉=’’&&&&& AND&& 日期字段&’’
ISNULL转换的例子:
WHERE ISNULL(字段,’’)&&’’应改为:WHERE字段&&’’
WHERE ISNULL(字段,’’)=’’不应修改
WHERE ISNULL(字段,’F’) =’T’应改为: WHERE字段=’T’
WHERE ISNULL(字段,’F’)&&’T’不应修改
C、 不要对索引字段使用函数
WHERE LEFT(NAME, 3)='ABC' 或者WHERE SUBSTRING(NAME,1, 3)='ABC'
WHERE NAME LIKE 'ABC%'
日期查询的例子:
WHERE DATEDIFF(DAY, 日期,'')=0应改为:WHERE 日期 &='' AND 日期 &'‘
WHERE DATEDIFF(DAY, 日期,'')&0应改为:WHERE 日期 &'‘
WHERE DATEDIFF(DAY, 日期,'')&=0应改为:WHERE 日期 &'‘
WHERE DATEDIFF(DAY, 日期,'')&0应改为:WHERE 日期&='‘
WHERE DATEDIFF(DAY, 日期,'')&=0应改为:WHERE 日期&='‘
D、不要对索引字段进行多字段连接
WHERE FAME+ ’.’+LNAME=‘HAIWEI.YANG’
WHERE FNAME=‘HAIWEI’ AND LNAME=‘YANG’
8、 注意连接条件的写法
多表连接的连接条件对索引的选择有着重要的意义,所以我们在写连接条件条件的时候需要特别的注意。
A、多表连接的时候,连接条件必须写全,宁可重复,不要缺漏。
B、 连接条件尽量使用聚集索引
C、 注意ON部分条件和WHERE部分条件的区别
9、 其他需要注意的地方
经验表明,问题发现的越早解决的成本越低,很多性能问题可以在编码阶段就发现,为了提早发现性能问题,需要注意:
A、程序员注意、关心各表的数据量。
B、 编码过程和单元测试过程尽量用数据量较大的数据库测试,最好能用实际数据测试。
C、 每个SQL语句尽量简单
D、不要频繁更新有触发器的表的数据
E、 注意数据库函数的限制以及其性能
10、学会分辩SQL语句的优劣
自己分辨SQL语句的优劣非常重要,只有自己能分辨优劣才能写出高效的语句。
A、&查看SQL语句的执行计划,可以在查询分析其使用CTRL+L图形化的显示执行计划,一般应该注意百分比最大的几个图形的属性,把鼠标移动到其上面会显示这个图形的属性,需要注意预计成本的数据,也要注意其标题,一般都是CLUSTERED INDEX SEEK 、INDEX SEEK 、CLUSTERED INDEX SCAN 、INDEX SCAN 、TABLE SCAN等,其中出现SCAN说明语句有油画的余地。也可以用语句
SET SHOWPLAN_ALL ON
要执行的语句
SET SHOWPLAN_ALL OFF
查看执行计划的文本详细信息。
B、用事件探查器跟踪系统的运行,可疑跟踪到执行的语句,以及所用的时间,CPU用量以及I/O数据,从而分析语句的效率。
C、可以用WINDOWS的系统性能检测器,关注CPU、I/O参数
四、测试、试运行、维护阶段
测试的主要任务是发现并修改系统的问题,其中性能问题也是一个重要的方面。重点应该放在发现有性能问题的地方,并进行必要的优化。主要进行语句优化、索引优化等。
试运行和维护阶段是在实际的环境下运行系统,发现的问题范围更广,可能涉及操作系统、网络以及多用户并发环境出现的问题,其优化也扩展到操作系统、网络以及数据库物理存储的优化。
这个阶段的优花方法在这里不再展开,只说明下索引维护的方法:
A、&&&&&&&&&&&&& 可以用DBCC DBREINDEX语句或者SQL SERVER维护计划设定定时进行索引重建,索引重建的目的是提高索引的效能。
B、&&&&&&&&&&&&&& 可以用语句UPDATE STATISTICS或者SQL SERVER维护计划设定定时进行索引统计信息的更新,其目的是使得统计信息更能反映实际情况,从而使得优化器选择更合适的索引。
C、&&&&&&&&&&&&&& 可以用DBCC CHECKDB或者DBCC CHECKTABLE语句检查数据库表和索引是否有问题,这两个语句也能修复一般的问题。
D、&&&&&&&&&&&&&
五、&&&&&&&&&&&& 网上资料中一些说法的个人理解
1、 “应尽量避免在 WHERE 子句中对字段进行 NULL 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
SELECT ID FROM T WHERE NUM IS NULL
可以在NUM上设置默认值0,确保表中NUM列没有NULL值,然后这样查询:
SELECT ID FROM T WHERE NUM=0”
个人意见:经过测试,IS NULL也是可以用INDEX SEEK查找的,0和NULL是不同概念的,以上说法的两个查询的意义和记录数是不同的。
2、 “应尽量避免在 WHERE 子句中使用!=或&&操作符,否则将引擎放弃使用索引而进行全表扫描。”
个人意见:经过测试,&&也是可以用INDEX SEEK查找的。
3、 “应尽量避免在 WHERE 子句中使用 OR 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
SELECT ID FROM T WHERE NUM=10 OR NUM=20
可以这样查询:
SELECT ID FROM T WHERE NUM=10
SELECT ID FROM T WHERE NUM=20”
个人意见:主要对全表扫描的说法不赞同。
4、 “IN 和 NOT IN 也要慎用,否则会导致全表扫描,如:
SELECT ID FROM T WHERE NUM IN(1,2,3)
对于连续的数值,能用 BETWEEN 就不要用 IN 了:
SELECT ID FROM T WHERE NUM BETWEEN 1 AND 3”
个人意见:主要对全表扫描的说法不赞同。
5、 “如果在 WHERE 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
SELECT ID FROM T WHERE
可以改为强制查询使用索引:
SELECT ID FROM T WITH(INDEX(索引名)) WHERE ”
个人意见:关于局部变量的解释比较奇怪,使用参数如果会影响性能,那存储过程就该校除了,我坚持我上面对于强制索引的看法。
6、 “尽可能的使用 VARCHAR/NVARCHAR 代替 CHAR/NCHAR ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。”
个人意见:“在一个相对较小的字段内搜索效率显然要高些”显然是对的,但是字段的长短似乎不是由变不变长决定,而是业务本身决定。在SQLSERVER6.5或者之前版本,不定长字符串字段的比较速度比定长的字符串字段的比较速度慢很多,所以对于那些版本,我们都是推荐使用定长字段存储一些关键字段。而在2000版本,修改了不定长字符串字段的比较方法,与定长字段的比较速度差别不大了,这样为了方便,我们大量使用不定长字段。
7、 关于连接表的顺序或者条件的顺序的说法,经过测试,在SQL SERVER,这些顺序都是不影响性能的,这些说法可能是对ORACLE有效。
&出处忘了:作者见谅
随着Internet的日益普及,现在基于B/S结构的大型应用越来越多,可如何对这些应用进行测试成为日益迫切的问题。有许多测试人员来信问我B/S的测试如何做,由于工作较繁忙,对大家提出的问题也是头痛医头脚痛医脚,没有对WEB的测试过程做一个整体的概述。希望通过本篇能够让大家了解大型Web应用是如何来进行测试的。
&&& B/S下的功能测试比较简单,关键是如何做好性能测试。目前大多数的测试人员认为只要跑一些测试工具证明我的产品是可以达到性能的就ok了,为了证明而去测试是没有任何价值的,关键是要发现产品性能上的缺陷,定位问题,解决问题,这才是测试要做的。
&&& 首先我们从两个方面分析如何进行WEB测试,从技术实现上来讲一般的B/S结构,无论是.NET还是J2EE,都是多层构架,有界面层,业务逻辑层,数据层。而从测试的流程上来说,首先是发现问题,分析问题,定位问题,再由开发人员解决问题。那么B/S的结构的测试如何来做?
&&& 如何发现问题是我首先要介绍的,在做WEB测试之前你需要一些资料,比如产品功能说明书,性能需求说明书,不一定很完善,但一定要有,明确测试目标,这是基本的常识,可是我往往看到的是已经开始动手测了,但还不知自己的系统要达到的性能指标是什么。这里我简单讲一下测试的性能指标:
l&&&&&&& 通用指标(指Web应用服务器、数据库服务器必需测试项):
* ProcessorTime: 指服务器CPU占用率,一般 平均达到70%时,服务就接近饱和;
* Memory Available Mbyte :&& 可用内存数,如果测试时发现内存有变化情况也要注意,如果是内存泄露则比较严重;
* Physicsdisk Time& : 物理磁盘读写时间情况;
l&&&&&&& Web服务器指标:
* Avg Rps: 平均每秒钟响应次数=总请求时间 / 秒数;
* Avg time to last byte per terstion (mstes):平均每秒业务角本的迭代次数 ,有人会把这两者混淆;
* Successful Rounds:成功的请求;
* Failed& Rounds :失败的请求;
* Successful& Hits :成功的点击次数;
* Failed& Hits :失败的点击次数;
* Hits Per Second :每秒点击次数;
* Successful& Hits Per Second :每秒成功的点击次数;
* Failed& Hits Per Second :每秒失败的点击次数;
* Attempted& Connections :尝试链接数;
l&&&&&&& 数据库服务器指标:
* User 0& Connections :用户连接数,也就是数据库的连接数量;
* Number of deadlocks:数据库死锁;
* Butter Cache hit :数据库Cache的命中情况;&
上面的指标只是一些通用的指标,起到抛砖引玉的作用,对于不同的应用你还必需作相应的调整,比如程序使用的是.NET技术的,则必需加入一些针对性的测试指标。对于这些指标的详细了解,你可以参考Windows 下面的 SystemMonitor的帮助与LoadRunner、ACT的帮助。对于发现问题,指标的设置非常重要,它会帮你定性的发现一些错误。对于定性的压力测试我就不做过多的分析,工具很多,流行的主要有LoadRunner,ACT,WAS,WebLoad,各个工具有它的使用范围,其中我各个认为LoadRunner 最全面,它提供了多种协议的支持,对复杂的压力测试都可以胜任,WAS与ACT则对微软的技术支持的比较好,其中WAS支持分布式机群测试,ACT则是与.NET集成比较好,支持ViewState (.NET 下控件缓存的支持) 的测试,当时我用时,其它测试工具还不支持,现在应该支持了吧,呵呵。在这一阶段测试你要不断的跟据系数的测试目标进行变化,一开始由于系统过于庞大,所以我们要分成若干个子系统,各个子系统的性能目标必需明确,主要是并发指标定一个阀值,同时设定一些与系统相关的测试参数,应用服务器,数据库服务器都要有,对达不到阀值的与一些通用参数有问题的子系统进行深入分析。比如它的并发达不到你的要求,证明子系统性能有问题,或是数据库用户连接过高,程序没有释放用户连接等等。这个我们要对子系统进行详细测试,由于B/S 结构下,图片的请求对性能的影响较大,所以我们对子系统测试时要分两个部分进行,一、非程序部分,即图片等等;二、应用程序本身。通过事务或函数的分离,可以把这两块实现单独的测试,具体做法参考各个工具的手册,我这里就不做说明。对子系统的测试参数的设置要求则更高,它有助你后面精确的定位问题,比如对异常,死锁,网络流量等等前面没有注意到的情况的增加,同时你要注意增加测试参数的收集对系统的性能影响比较大,所以一般不要超过10个,刚刚介绍的整体的性能测试指标也不要增加很多,这样影响会小一点。最后在这一阶段要说明的是数据库的数据量会很大程度的影响性能,所以要根据前面的性能需求说明书向数据库中模拟相应的数据量,来进行测试,这样才有更高的可信度。
&&&&&& 上面所说的是对问题的发现,下面就是分析问题原因,这一步的要求比较高,一般由测试人员与程序员配合完成,当然如果你有相当的开发经验,再做这方面的测试,就更为难得。下面我们说说如何精确定位问题,出现问题的可能性可能有很多种,大致分以下几种,一、性能达不到目标;二、性能达到目标,但有一些其它的问题,比如异常,死锁,缓存命中过低,网络流量较大;三、服务器稳定性的问题,比如内存泄漏……。要发现这些问题起马的要求要有一款使用的比较称心的性能分析与优化工具,比如微软的.NET下就有自己开发的工具,对Borland的Java开发工具中也有类似的工具,但我个人认为更好的工具是Rose下的Purify与Quantify,主要是他对.net 与java ,C++都有支持,而且分析效果特别专业,我们先了解一下Rational Purify,& Rational Purify 能自动找出Visual C/C++ 和Java 代码中与内存有关的错误,确保整个应用程序的质量和可靠性。在查找典型的Visual C/C++ 程序中的传统内存访问错误,以及Java,C# 代码中与垃圾内存收集相关的错误方面;Rational Quantity 则是一款针对函数级的性能分析利器,使用它你可以从图形化的界面中得到函数调用的时间,百分比与次数,以及子函数所占时间,使你可以更快的定位性能瓶颈。
我们先说性能优化与异常的处理,性能优化有一个原则,即用时间比例最大的进行优化,效果才最明显,比如有个函数它的执行时间为30秒,如果你优化了一百倍则执行时间为0.3秒,提升了29.7秒,而如果它的执行时间为0.3秒,优化后为0.003秒,实际提升了0.297秒,提升的效果并不明显,而且写过程序的人都知道,后者性能优化的代价更大。在性能优化的过程中,一般是先数据库,后程序,因为数据库的优化不需要修改程序,修改的风险很小。但如何才能确定是数据库的问题,这就需要技巧,在使用Quantity时,你一路分析下去,大多数最终会发现,是数据库查询函数占用时间比较大,比如什么,SqlCmd.ExecuteNoQuery等等数据库执行函数,这时你就需要分析数据库,呵呵。数据库的分析原则是先索引,后存储过程,最后表结构视图的优化,索引的优化是最简单也是通常最有效的方法,如果合理的使用会带来意想不到不到的效果。在这里我要给大家简单的介绍一下我的最爱,SQLProfile,SQL查询分析器,Precise,SQLProfile是一个SQL语句跟踪器,可以跟踪程序流程使用的SQL语句与存储过程,结合查询分析器对SQL的分析,可以对索引的优化做出很好的判断,但索引也不是万能的,在增删改较多的表,索引过多会引起这些操作的性能下降,所以判断还是需要一定的经验。同时针对用户使用频度最高的SQL进行优化也是最行之有效的,这时我则需要Precise,它可以观测某一个较长时间内的SQL语句的执行情况。数据库优化的潜能挖光后,如果还是达不到性能要求或是还有问题,则要从程序来进行优化,这是程序员做的事,测试人员要做的,就是告诉他们,哪个函数执行过多引起了性能下降,比如异常过多,某个循环过多,或是DCOM调用过多等等,但说服程序员也是一件不容易的事,你要在这一阶段做的出色一定要有几年的编程经验,并且要让程序员感到听你的性能会有提升,这是一件很不容易的事情哦。
内存的分析,一般是一个长期分析的过程,要做好不容易,首先要有长期奋战的准备,其次内存泄漏的分析最好是放在单元测试之中同步进行,而不是要等到最后再去发现问题,当然出了问题也只好面对,一般这类问题都是在服务器运行了很久才暴露出来,一旦发现问题后,则需要定位问题,分析的原则采用子系统相互独立运行,找到最小问题的系统集,或是借助内存分析工具观察内存对象情况,初步定位问题,再用Purify进行运行时分析,通常C++ 内存问题比较多,Java与.NET比较少,一般由GC不合理引起。C++的内存错误就比较多了,主要常见的有:
1、 Array Bounds Read (ABR) :数组越界读
2、 Array Bounds Write (ABW):数组越界写
3、 Beyond stack Read (BSR):堆栈越界读
4、 Free Memory Read(FMR):空闲内存读
5、 Invalid pointer Read(IPR):非法指针阅读
6、 Null Pointer Read(NPR):& 空指针阅读
7、& Uninitialized Memory Read(UMR):未初始化内存读写
8、 Memory Leak:内存泄漏
注:如果需要更多的信息,可以参见Purify的帮助信息。
&顺便提一句,为什么我要说单元测试时做这个比较好,由于单元测试针对的是单一功能,这时结合单元测试案例做内存分析会更快的定位问题,同时由于问题较早的发现,则后期的风险则会减少,当然如果结合代码覆盖工具PureCoverage 来做就更完美了,呵呵。
&&&&&& 完成此文,已经是凌晨了,也算是回答了前一段时间提出要进行B/S结构测试又无从下手的朋友的要求,在这里要向大家表达一下歉意,由于工作比较忙,难免对大家的来信有所疏漏,请大家原谅。此文的要求的读者,对测试工具有所了解,希望进入更深测试的同仁,希望我的文章给大家带来帮助,同时也借此文表达一些曾经帮助过我的朋友与同事。
注:本篇只是对B/S应用的测试过程作一个整体的描述,对某一个阶段使用的工具只是作大概的介绍,你也可使用你比较熟悉的工具达到相同的目标。
在比较大规模的网络应用或者对安全有一定要求的应用中,通常需要对系统的日志进行记录分类并审核,默认情况下,每个系统会在本地硬盘上记录自己的日志,这样虽然也能有日志记录,但是有很多缺点:首先是管理不便,当服务器数量比较多的时候,登陆每台服务器去管理分析日志会十分不便,其次是安全问题,一旦有入侵者登陆系统,他可以轻松的删除所有日志,系统安全分析人员不能得到任何入侵信息。
因此,在网络中安排一台专用的日志服务器来记录系统日志是一个比较理想的方案。本文以FreeBSD下的syslog为例,介绍如何利用freebsd的syslogd来记录来自UNIX和windows的log信息。
一、记录UNIX类主机的log信息
首先需要对Freebsd的syslog进行配置,使它允许接收来自其他服务器的log信息。
在/etc/rc.conf中加入:
syslogd_flags="-4 -a 0/0:*"
说明:freebsd的syslogd参数设置放在/etc/rc.conf文件的syslogd_flags变量中
Freebsd对syslogd的默认设置参数是syslogd_flags="-s",(可以在/etc/defaults/rc.conf中看到)
默认的参数-s表示打开UDP端口监听,但是只监听本机的UDP端口,拒绝接收来自其他主机的log信息。如果是两个ss,即-ss,表示不打开任何UDP端口,只在本机用/dev/log设备来记录log.
修改后的参数说明:
-4 只监听IPv4端口,如果你的网络是IPv6协议,可以换成-6
-a 0/0:* 接受来自所有网段所有端口发送过来的log信息。
如果只希望syslogd接收来自某特定网段的log信息可以这样写:-a 192.168.1.0/24:*
-a 192.168.1.0/24:514或者-a 192.168.1.0/24表示仅接收来自该网段514端口的log信息,这也是freebsd的syslogd进程默认设置,也就是说freebsd在接收来自其他主机的log信息的时候会判断对方发送信息的端口,如果对方不是用514端口发送的信息,那么freebsd的syslogd会拒绝接收信息。即,在默认情况下必须:远程IP的514端口 发送到本地IP的514,
在参数中加入*,表示允许接收来自任何端口的log信息。这点,在记录UNIX类主机信息的时候感觉不到加不加有什么区别,因为UNIX类主机都是用514端口发送和接收syslog信息的。但是在接收windows信息的时候就非常重要了。因为windows的syslog软件不用514端口发送信息,这会让默认配置的syslogd拒绝接收信息。笔者同样在linux系统下用linux的syslogd来配置log服务器,发现linux下的syslogd就没有那么多限制,只要给syslogd加上-r参数,就可以接收来自任何主机任何端口的syslog信息,在这方面来说freebsd的默认配置安全性要比linux稍微高一点。
修改好syslogd参数后,我们需要修改一下/etc/syslog.conf文件,指定log信息的存放路径,
比如你要记录其他系统的远程登陆登出信息并指定日志存放路径,则需要修改以下行:
authpriv.* /var/log/testlog
这表示把系统的登入登出日志(包括本机系统登陆登出日志)存放到/var/log/testlog文件中。
当然,这是最简陋的做法,因为这样会把所有服务器的登陆登出信息存放在一个文件中,察看的时候很不方便,通常的做法是用一个脚本,对接收到的信息进行简单的分拣,再发送到不同的文件。
如下设置:
authpriv.* |/var/log/filter_log.sh
在记录目标前面加上“|”表示把接收到的信息交给后面的程序处理,这个程序可以是一个专门的日志处理软件,也可以是一个自己编写的小的脚本,举例:
#!/bin/sh
read stuff
SERVER=`echo $stuff |awk ‘{print $4}’`
echo $stuff && /var/log/login_log/$SERVER.log
这个简单的脚本以IP作为分类依据,先用read读取log信息,用awk取出第四字段(即IP地址或者主机名所在的字段),以该字段为文件名存放该主机的日志。
这样一来,来自192.168.1.1的log会记录到192.168.1.1.log文件中,来自192.168.1.2的log会被记录在192.168.1.2.log文件中,分析和归类就比较方便了。当然这是一个最简单的例子,读者可以根据自己的需求写出更好的脚本,甚至把log信息分类后插入数据库中,这样日志的管理和分析就更方便了。
最后重启一下syslogd服务,让配置生效:
/etc/rc.d/syslogd restart
OK,服务端的配置完成。现在配置一下客户端:
这里所说的客户端,就是发送自己的日志到远程日志服务器上的主机。
修改/etc/syslog.conf文件:
我们举例你只要记录系统登入登出日志到远程日志服务器上,那么只需要修改以下一行:
authpriv.* @192.168.10.100
这里的192.168.10.100就是log服务器的IP,“@”符号表示发送到远程主机。
OK,重启一下syslog服务:
Linux: /etc/init.d/syslogd restart
BSD: /etc/rc.d/syslogd restart
用logger测试一下是否配置成功:
logger –p authpriv.notice “Hello,this is a test”
到log服务器上去看看,“Hello,this is a test”应该已经被记录下了。最后在客户机上登陆登出几次,看看真实的authpriv信息是否也被成功的记录下。
二、Windows日志的记录
对于UNIX类主机之间记录日志,由于协议、软件和日志信息格式等都大同小异,因此实现起来比较简单,但是windows的系统日志格式不同,日志记录软件,方式等都不同。因此,我们需要第三方的软件来将windows的日志转换成syslog类型的日志后,转发给syslog服务器。
介绍第三方软件evtsys (全称是evntlog to syslog)
下载地址:
文件才几十K大小,非常小巧,解压后是两个文件evtsys.dll和evtsys.exe
把这两个文件拷贝到 c:\windows\system32目录下。
打开Windows命令提示符(开始-&运行 输入CMD)
C:\&evtsys –i –h 192.168.10.100
-i 表示安装成系统服务
-h 指定log服务器的IP地址
如果要卸载evtsys,则:
net stop evtsys
启动该服务:
C:\&net start evtsys
打开windows组策略编辑器 (开始-&运行 输入 gpedit.msc)
在windows设置-& 安全设置 -& 本地策略 -&审核策略 中,打开你需要记录的windows日志。evtsys会实时的判断是否有新的windows日志产生,然后把新产生的日志转换成syslogd可识别的格式,通过UDP 3072端口发送给syslogd服务器。
OK,所有的配置windows端配置完成,现在配置一下syslogd的配置文件,
参数的配置和上面相同,所不同的是evtsys是以daemon设备的方式发送给 syslogd log信息的。因此,需要在/etc/syslog.conf中加入:
daemon.notice |/var/log/filter_log.sh
关于syslog 记录设备和记录等级方面的知识可以参考syslog文档。
OK,所有配置设置完成。
Linux 、BSD和windows上的系统日志都可以统一记录到一台日志服务器上轻松管理了。
Syslog常被称为系统日志或系统记录,是一种用来在互联网协定(TCP/IP)的网络中传递记录档讯息的标准。这个词汇常用来指涉实际的syslog 协定,或者那些送出syslog讯息的应用程式或数据库。
syslog协定属于一种主从式协定:syslog发送端会传送出一个小的文字讯息(小于1024字节)到syslog接收端。接收端通常名为“syslogd”、“syslog daemon”或syslog服务器。系统日志讯息可以被以UDP协定及╱或TCP协定来传送。这些资料是以明码型态被传送。不过由于SSL加密外套(例如Stunnel、sslio或sslwrap等)并非syslog协定本身的一部分,因此可以被用来透过SSL/TLS方式提供一层加密。
syslog通常被用于资讯系统管理及资安稽核。虽然它有不少缺陷,但仍获得相当多的装置及各种平台的接收端支援。因此syslog能被用来将来自许多不同类型系统的日志记录整合到集中的储存库中。
&& 在ORACLE数据库中,LOB(Large Objects—大对象)是用来存储大量的二进制和文本数据的一种数据类型(一个LOB字段可存储可多达4GB的数据)。目前,它又分为两种类型:内部LOB和外部LOB。内部LOB将数据以字节流的形式存储在数据库的内部。因而,内部LOB的许多操作都可以参与事务,也可以像处理普通数据一样对其进行备份和恢复操作。Oracle8i支持三种类型的内部LOB:BLOB(二进制数据)、CLOB(单字节字符数据)、NCLOB(多字节国家字符数据)。其中CLOB和NCLOB类型适用于存储超长的文本数据,BLOB字段适用于存储大量的二进制数据,如图像、视频、音频等。
&& 可通过以下语句可查看clob字段的信息:select&& dbms_lob.substr(col_lob)&& from&& table_name

我要回帖

更多关于 手机怎么样清除缓存 的文章

 

随机推荐