一次处理web页面缓慢的思考

    上周五,在现场处理一个web页面缓慢的问题,主要功能是显示非常多的统计数据,画出很多图表。听说是新加了一个功能块后,页面变的很慢,于是我先建议关闭新加的功能,后来还是很慢;于是建议分块关闭页面上的功能。策略是先按大块找问题出现的地方,再进入块找细节问题,类似2分法,当然也可以先关闭一半页面功能。慢慢变的快了一点,最后全关了,才秒出。

    看来不仅是局部问题了,我开始仔细分析代码,页面上的功能主要就是各种各样的查询SQL语句,用的是Oracle,主要问题有以下方面:

    1.很多统计的查询条件是 id like '____SH' and name like '%上海%'
    了解下来,这是一个类型的的数据,但是并没有单独的类型字段,后期只能用这样的条件来区分出来。
    所以问题的根源是:数据字段设计缺失,应该设计特有的类型字段;这两个字段都无法利用上索引来提高查询速度。因为不确定的部分在前面,如果是'上海%'还有可能。
    解决方法是:instr的效率在有索引的情况下应该高于like,把前者用subStr截取后='SH',后者用instr>0的方法,几乎没有明显的提高。另一终极处理就是新建类型字段,一次性处理历史数据,新数据可以完善前台功能,或者数据库上建触发器,新增数据时按条件置类型字段,新字段上当然建好索引。

    2.很多统计的主外键关联是trim(pk)=trim(id)
    了解下来,因为有些数据是其它地方交换过来的,提供的数据不规范,前后可能有空格,造成查不到需要的数据。
    所以问题是:规范提供的数据,入库的数据一定要是标准的。外键上的索引也用不上,因为带有函数,总不至于都建函数索引吧。
    解决方案:一方面查找历史数据,也许只是个别地方提供的数据有问题,要求修改。当然可以先处理老数据,再用触发器来预处理新数据,但这绝不好办法。

    3.有一个统计是按提前,正常,超期分类得到各自数据,总数又用了一个sql去算,为何不直接把三个分类数据加起来呢?
    还发现一个重要的业务ID用了distinct,我问这个会有重复吗?一查字段是主键。
    还发现三个数据,都有一个完成的字段判断,写在每类的case when里面,为何不写在查询外面的where条件里呢?既然都有这个case when的条件?
   
    4.发现所有的统计是从年初到当天,而每一个sql语句里都有sysDate转日期。
    通常我们页面呈现的数据是有一个日期范围的,或者当月,或者一个月内,根据业务与数据情况而定,不可能没有限制。我们查询股票交易都有很严格的时间限制,数据实在是太多了,历史数据也要求开始与结束不通过比如1个月。
    例子是极端的情况,但当年的数据,也许后面太多会计算很慢,要考虑一下。当然这个sql中的今日,为何不能在外面算好,统一为常量传给数据库计算?而现在每个SQL都要再算一下。
    因为数据的日期精确到时分秒,所以我考虑是不是做一个日期的函数索引?只到天,这样在条件中也使用日期函数,也许会快一点。

    5.一个数据表的查询条件一样,但有和不同其它表的关联统计,目前是一个个独立的SQL,是否考虑把这些都join在一起,一个语句中返回结果,可以合并一些查询SQL。因为使用连接池,也许效果不太明显。我的习惯是用一条SQL搞定数据,而不要返回后再各种处理,充分利用数据库的功能。

    6.页面中的统计太多了,局部加载也是一个方案,当鼠标拉下来的时候,再进行查询展示屏幕后部分功能。

    7.脚本后置,异步获取数据,先让页面主体结构出来也是一个方案。

    8.提前缓存查询结果也是一个策略,考虑到数据实时性要求不高时,可以提前在后台计算出数据。唯独注意系统启动时必须计算一次,否则没数据就尴尬了。

    9.其它情况,完全处理好后再补充,欢迎交流各种心得。

    不过太关注细节是没前途的,呵呵~

猜你喜欢

转载自herman-liu76.iteye.com/blog/2368274