关于性能优化若干问题报告

关于性能优化若干问题报告

 

公司要我出一个关于“关贸通”性能分析的报告,正好我也希望把我理解的一些性能优化方面的东西整理一下希望大家帮我指出当中的问题,也算是和大家一起交流一下经验。

报告将通过分析程序操作页面大小,数据库访问次数,代码的优化等方面对“关贸通”页面性能问题作出判断,并向开发人员提供优化方法。

 

一、页面优化

    页面作为用户接口,是最直接和用户打交道的地方,用户在使用上最直观的认识也是由程序页面开始,所以给用户一个良好的使用体验就由为重要,一个简单良好的用户界面也能使得用户持续对程序保持信心。

 

1、   简化页面结构

    很多页面为了保证结构位置的正确,使用大量的DIVTable作为容器来控制位置,但是这就会给页面带来一些业务无关的字节,这些字节会占用带宽,同时浏览器在分析这些结构时也需要占用一定的机器时间,而且当我们使用JS脚本处理页面对象时往往计算机也需要花费更多时间通过递归更多对象去找到这个需要的对象(这个会再之后的脚本油画中详细描述),这就会给用户访问时带来一定的延时,特别是对于那些通过外网访问的用户。当然随着互联网技术的发展,现在网络的速度越来越快,机器性能也越来越好,这些东西慢慢的都被忽略掉了,特别是对于内网用户而言性能提升几乎可以被忽略不计。

2、   尽量少用视图状态

    我们都知道web页面都是无状态的,简单的讲当一个请求在服务器端被接收到后,服务器端会为这个请求建立一个独立的线程去处理这个请求,当请求处理完成后,这个线程也就消失了,在个线程里的所有状态也都消失了,当这个页面再次请求时,此页面之前的状态服务器是没有办法知道的(当然你可以通过在服务器记录Session或者使用cookie记录状态但这个都是被动的),所以微软搞了一个“视图状态”来记录当前页面上各个控件的状态,并把它放在一个隐藏控件里来回的传递,它的优点是显而易见的,开发人员不需要再去关心任何的状态,在线程中所有的控件状态都已经帮你处理好了,开发人员只需要简单调用即可。但是“视图状态”却会给页面带来大量的状态数据,再加上很多程序使用Post back(提交)方法回传数据,这样“视图状态”就会被来回传递,当页面使用了大量没有关闭视图状态的Asp.net控件时状态数据更是会大的下人,这大大增加了页面流量。我在做很多网站时(特别是在早期firework 1.1的时候)都被明确要求关闭“视图状态”以减少用户访问时来回传递的字节,提高访问速度。当然对于内网用户提升的优势并不明显。

3、   将一些功能放到客户端去处理

    很多程序员为了开发方便,将许多功能都写在了服务端,这样开发上确实便捷了,但是这使得很多功能的实现都必须由客户端页面POST到服务端,服务端处理完成后再发送给客户端,这即增加了来回传递数据的开销,更重要的是当有多个用户同时访问时服务器压力就会增加,现在的服务器已经相当先进,对数据处理的速度非常的快,但是对于连接数量仍然是瓶颈,据我所知NET方式(不是指.net)下网络终端需要维持一个连接端口其开销是很大的一个设备能开的端口号也是有限的,每次连接时(TCP方式)还需要等待双方都得到对方连接成功信号(这个是网络设备方面的知识,我不是学这个的所以可能有偏差,我只从编程角度的理解),过多的连接请求将导致多个请求被要求排队等待甚至被丢弃。当然这可以通过增加服务器数量,用均衡设备将请求分散到多个服务器上的方法来解决。但是如果没有这样的条件,最简单的方法就是最大可能的减少请求次数。

    最简单也是最常用的方法就是将一些处理推到客户端去完成,JavaScript是个很好的选择,可以在js中完成的操作就不以Post back方式丢回服务端,以尽量减少Post back回传的原则来开发程序。

        Ajax也是现今很流行的做法,它每次回传时只将需要的数据Post回去,而且异步处理的优势使得再回传数据时可以去做一些其他的事情同步完成。

4、   减少弹出页面

一个IE内核窗口是非常占用资源的,而且每次弹出页面都等于一次完整的页面请求。在我之前做的几个家网站里,很多都是直接使用DIV作为弹出层,在页面初次打开时弹出层的框架已经被载入,需要弹出时只需要使用Ajax去请求数据即可,不用去请求整个页面也不需要再打开一个IE浏览器。

还有一个更简单的方法,就是再页面打开时就将需要弹出的数据预先载入到客户端浏览器的内存中,当用户需要访问时直接使用js将缓冲的数据添入弹出层即可。

5、   图片

页面尽量少用图片特别是未压缩过的图片,图片除了都比较大以外还非常占用连接资源,因为每个图片都是一个连接请求,有报道说可以考虑使用将图片合并为一张大图片然后使用Image Map的方法去分割图片显示,此方法我没有具体使用过,有兴趣可以自己尝试一下。

 

总之,无论使用何种方法,要提高浏览效率,减轻服务器压力关键的问题就是最大限度的减少客户端对服务器端的请求次数。在客户端可以完成的事情就不回传给服务端。

 

二、数据库访问

数据库访问优化也是一个提高页面速度的关键点,甚至我认为是最关键的一点。在我开发过的几个程序里很多都是因为查询数据库拖慢了整个程序执行速度。一个高效的查询有时甚至可以提高几倍于以前的执行速度。

1、   减少数据库连接

和之前所说的减少页面请求一样,计算机要建立并维持一个连接是非常耗时,耗资源的。所以当需要执行多个SQL语句时尽量把他们放在一个连接中处理,或者放在一个存储过程中来返回结果。

2、   查询语句中加入WITH(NOLOCK)

WITH(NOLOCK)大家应该都不陌生,如果不清楚我这里简单介绍一下它的作用,所有的数据库为了保证数据的完整性都有一个锁机制来控制并发情况下数据修改访问的逻辑。锁机制对数据库而言是很关键的它保证了记录不会在并发下被脏写脏读,但有的时候也会给数据库访问带来一些麻烦,比较明显的就是当数据库执行一句UPDATE语句时这个记录就会被加入一个排他锁(锁级别按不同数据库不同设置下不同),当另一个用户尝试访问这条记录时就会被要求等待,直到UPDATE执行完成。另一个情况,当一个用户在SELECT一个较大的表时,在未执行完成前,查询所在页(PAGE)被加上了S锁(好像叫共享锁),这个锁我理解为只读锁,也就是当前页数据仍然可以被读取但是无法被UPDATE等更新操作。当记录被加上了这些锁后其他查询就必须等待加这些锁的线程完成后开锁才能执行,这个时候页面其实也是处在等待状态下的,所以在一些对脏数据不敏感的SELECT语句中加入WITH(NOLOCK)就可以再执行语句时自动打开那些锁,但是带来的问题就是可能产生脏读。这个选择在程序员这边,具体就要看业务需求了。

3、   减少表的连接

多表连接会拖慢查询,原因我想不解释大家也应该很清楚,虽然使用主键作为连接字段性能非常的好,但是毕竟每条记录还是需要执行一次计算,记录数量巨大时性能差别就体现出来了,很多设计人员考虑到业务耦合度的问题,将一些可配置字段独立存在于一张表中以便降低耦合,这样当这些配置数据改动时只需要改动配置表即可,但是这也给查询带来的麻烦,一条记录的查询可能被要求关联多张配置表,有时候可以考虑将一些数据冗余到一张表里以提高查询速度,但是这样带来的问题是更新配置信息时可能就需要修改所有的记录。这是个博弈的过程,没有说那个方法更合适,一般按照具体需求来设计,如果你的记录表非常的巨大,而且修改的机会也不是很大时可以考虑使用这种冗余的方法。

这里捎带提一下,很多人在做查询时都会以为使用连接字符来连接两张表要比IN来的更快速,这似乎已经成了一个真理,但是有趣的是我做了一下实验,有两张表,用两个方法去关联,一个是通过内连接,一个是通过IN的方法,结果表明,当连接字段是主键时,两个查询方法性能一样,当连接字段为非主键时IN方法要比INNER JOIN快上近1半!为什么会这样呢?通过查看执行计划发现,当你使用IN时查询分析器会自动帮你分析为INNER JOIN方法,这就解释了为什么使用主键关联时查询性能会一样,当使用非主键关联时,使用IN方法优化器除了将它分析为INNER JOIN外还给这个非主键字段建立了一个Hash表(其实可以理解为建立了一个索引)这样再使用非主键关联时性能变得非常的好。这里只是提一下大家也可以自己试试。

 

对于数据库的优化,我认为着重点仍然考虑的是减少数据库连接,减少查询次数上,同时减少关联表的连接也是非常重要的,当然这些都需要在设计之初就开始考虑。

 

三、代码的优化

良好的代码习惯和优秀的代码机构,不仅可以大幅提升程序执行效率,同时代码的可维护性也可以帮助程序被快速的开发部署。

1JavaScript

对一个对象最好只使用一次document.getElementById等类似查找语句,然后将结果指向一个对象,这样下去调用时直接调用这个对象即可,类似于document.getElementByXXX的方法是通过递归所有页面对象去找的,就像我第一节里写的当页面中嵌套元素很多时执行性能就会有所下降。

如果可以使用JQuery的方法去查找对象,因为JQuery提供的查询方法提供了一个容器的参数,这样在每次查找时就可以定义在某个容器中找对象而不必整个页面递归。

如果可以我们应该提倡用户使用Firefox作为浏览器,虽然对于写惯.NET的开发人员会发现他的代码很多都不不能在FF浏览器中正常执行,但是实际上Firefox才是真正执行标准(好像是叫w3c标准)的,IE自己扩展的一些方法其实并没有在标准中虽然它有时确实很管用,而且从一些报道看,FF是脚本执行效率最高的一个浏览器。

2、后台代码

其实这个并没有什么好讲的,因为代码千奇百怪,可能都是有它的道理,并没有什么理由好讲,所以我这里只提几点最简单也最基本的东西。

1、少用Hash

如果是学计算机的上课的时候老师实际上都应该讲过,所谓哈希表就是用空间换时间的一种技术,他通过hash函数将某个Key一定范围hash函数的好坏就看这个一定范围了)内计算出一个值,其实我认为可以理解为地址,然后用这个地址去一击命中,虽然他的命中性能是很好,但是带来的它在创建时就必须首先为它打开一段很大的内存,留着让它命中,太多的hash表就会吃掉很多服务器内存。

2、少用运算符号操作String对象

String是值类型,但是众所周知它本质其实就是byte型数组,微软只是把他的符号给重载了,所以我们可以像值类型一样使用运算符去计算它,但是它本质上还是引用类型的,以+为例子,微软给这个符号重载为每次都new出一个新的byte[]然后按顺序去填入数据,这样就变为值类型了。所以当我们使用+号去连接两个字符串时,计算机就必须一次次的new出新数组然后一个个的写值。正确的方法是使用StringBuilder来替代+法运算。

3、少用SessionApplication对象

这些对象里的值会在很长的时间里维持在服务端内存里,我个人建议还是少用,毕竟连接多时,内存会被吃的很快。

4、不要使用重定向

很多开发人员会喜欢使用Response.Redirect去重定向页面,其实这样做效率非常的低,这个方法不会中止当前页面的执行,服务器必须执行完当前的页面再去跳转,正确的方法是使用Server.Transfer这样当前页面将被停止,直接转到目标页面。

 

其他的优化诸如少用递归,查询列表对象前最好先排序等都是应事而异,这里就不特别列出来说明了,具体需要结合业务逻辑找出最有效率的方法。

 

对于优化其实这些都是一些很基本的皮毛,但是有的时候却会带来比较意想不到的效果,当然还有很多我不知道的优化方法,也希望大家可以一起提出来,大家一起讨论,为以后的开发带来便利。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值