性能调优过程总结
摘要:本文档主要总结项目性能调优过程遇到的性能问题以及解决此性能问题所用到的方法及过程。
第一章.数据库调优
一、索引调整
问题发现:awr报告中 SQL ordered by Elapsed Time模块记录了sql的执行总时间,这里我们主要关注Elap per Exec(s):执行一次SQL的平均时间。
awr报告中我们发现下面两条语句执行时间过长
(1) select * from (select tmp.*,rownum rn from (select c.id, c.title, c.file_path, c.create_date,c.publish_date, c.dept_id, c.author, c.summary, c.is_top, c.top_order,c.is_picture, c.picture_path, c.type from cms_content c where c.catalog_id=:1and c.state=:2 and c.is_old_version=:3 and ( c.valid_date is null orc.valid_date > :4 ) and (c.id in (select business_id fromcms_content_right_role r where (r.right_id=:5 or r.right_id=:6 ) and((r.role_id=:7 and r.role_type=:8 ) or (r.role_id=:9 and r.role_type=:10 ) or(r.role_id=:11 and r.role_type=:12 ) or (r.role_id=:13 and r.role_type=:14 ) or(r.role_id=:15 and r.role_type=:16 ))) or c.ext40='0') order by c.create_datedesc) tmp where rownum < 6) where rn >= 1
(2) select * from (select tmp.*,rownum rn from ( select c.id , c.type , c.title , c.creator_id , c.state ,c.publish_check_user , c.create_date , c.publish_date , c.priority ,c.comment_count, c.content_url, c.is_can_comment, c.access_count fromcms_content c where c.site_id = :1 and c.publish_date > :2 and c.state >=:3 and c.is_old_version = :4 and c.state >= :5 and c.is_old_version = :6 and( c.valid_date is null or c.valid_date > :7 ) and (c.id in (selectbusiness_id from cms_content_right_role r where (r.right_id=:8 or r.right_id=:9) and ((r.role_id=:10 and r.role_type=:11 ) or (r.role_id=:12 andr.role_type=:13 ) or (r.role_id=:14 and r.role_type=:15 ) or (r.role_id=:16 andr.role_type=:17 ) or (r.role_id=:18 and r.role_type=:19 ) or (r.role_id=:20 andr.role_type=:21 ))) or c.ext40='0') order by c.publish_date desc) tmp whererownum <= 5) where rn >= 1
问题分析解决:
Sql语句1:查看sql语句1其主要是对cms_content表的查询,查看该表的索引:
CREATE INDEX IDX_CMS_CONTENT_CATALOG_ID ON CMS_CONTENT (CATALOG_ID);
CREATE INDEXIDX_CMS_CONTENT_PUBLISH_DATE ON CMS_CONTENT (PUBLISH_DATE);
拷贝此sql运行oracle执行计划
我们发现其执行时跑的IDX_CMS_CONTENT_CATALOG_ID索引,该索引为默认升序,花费时间过长,另外发现该sql还根据create_date字段进行排序,特此我调整索引如下:
CREATE INDEX IDX_CATALOG_ID_CREATE_DATE ON CMS_CONTENT (CATALOG_IDdesc,CREATE_DATE desc);
再次运行oracle执行计划:
Sql语句2:查看sql语句2 ,运行oracle执行计划
发现其跑的是IDX_CMS_CONTENT_PUBLISH_DATE索引查询查询,该索引为默认升序,但该sql查询语句为降序查询,特此我们调整索引为降序索引:
CREATE INDEX IDX_CMS_CONTENT_PUBLISH_DATE ON CMS_CONTENT (PUBLISH_DATEdesc);
再次执行oracle执行计划:
调整后的awr报告如下:
问题总结:编写sql时适当的增加索引,可以提高sql执行效率,选择使用单索引和联合索引会造成很大的区别,索引的升降序也会对sql执行效率有很大影响。
资料:http://blog.youkuaiyun.com/shellching/article/details/7655793
二、SQL语句修改
问题发现:awr报告中 SQL ordered by CPU Time模块记录了执行占CPU时间总和时间最长的TOP SQL,这里我们关注CPUTime(s):cpu花费时间
awr报告中主要显示下面语句cpu开销时间过长:
(1) select * from (select tmp.*, rownumrn from (select c.id, c.title, c.file_path, c.create_date, c.publish_date,c.dept_id, c.author, c.summary, c.is_top, c.top_order, c.is_picture,c.picture_path, c.type from cms_content c where c.catalog_id=:1 and c.state=:2and c.is_old_version=:3 and ( c.valid_date is null or c.valid_date > :4 )and (c.id in (select business_id from cms_content_right_role r where(r.right_id=:5 or r.right_id=:6 ) and ((r.role_id=:7 and r.role_type=:8 ) or(r.role_id=:9 and r.role_type=:10 ) or (r.role_id=:11 and r.role_type=:12 ) or(r.role_id=:13 and r.role_type=:14 ) or (r.role_id=:15 and r.role_type=:16 )))or c.ext40='0') order by c.create_date desc) tmp where rownum < 6) where rn>= 1
问题分析:拷贝此sql运行oracle执行计划:
我们发现此语句cpu cost时间过长,cpu开销时间时间过长是由于sql语句查询条件过于复杂引起,我们可以适当增加查询限制条件来减少cpu开销时间。在此增加限制条件AND c.create_date>?,调整sql如下:
select* from (select tmp.*, rownum rn from (select c.id, c.title, c.file_path,c.create_date, c.publish_date, c.dept_id, c.author, c.summary, c.is_top,c.top_order, c.is_picture, c.picture_path, c.type from cms_content c wherec.catalog_id=:1 AND c.create_date>:17 and c.state=:2 andc.is_old_version=:3 and ( c.valid_date is null or c.valid_date > :4 ) and(c.id in (select business_id from cms_content_right_role r where (r.right_id=:5or r.right_id=:6 ) and ((r.role_id=:7 and r.role_type=:8 ) or (r.role_id=:9 andr.role_type=:10 ) or (r.role_id=:11 and r.role_type=:12 ) or (r.role_id=:13 andr.role_type=:14 ) or (r.role_id=:15 and r.role_type=:16 ))) or c.ext40='0')order by c.create_date desc,id desc) tmp where rownum < 6) where rn >= 1
因为sql语句是根据create_date降序的,联合索引中的索引是有先后顺序之分,特此我们调整索引如下:
CREATEINDEX IDX_CREATE_DATE_CATALOG_ID ON CMS_CONTENT (CREATE_DATE desc,CATALOG_IDdesc);
再次执行oracle执行计划:
问题总结:编写sql时我们可以适当增加限制条件来减少cpu cost,建立联合索引也要注意联合索引中的索引顺序问题。
三、去除不必要的sql
问题发现:awr报告中SQLordered by Reads模块通过物理读对SQL语句进行排序。这显示引起大部分对这个系统进行读取活动的SQL,即物理I/O。当我们的系统如果存在I/O瓶颈时,需要关注这里I/O操作比较多的语句。awr报告中显示了个JDBC Thin Client连接查询语句过长,此语句如下:
select * fromportal_site_template where 1=1
问题分析:经排查当网站部件请求后台获取模板数据时会不停执行此命令,此sql语句没有任何意义,应该删除,经删除后的awr报告如下:
问题总结:SQL ordered by Reads模块通过物理读对SQL语句进行排序,应该尽量保持此处不要出现JDBC Thin Client连接查询。
第二章.WEB前台优化
一、404页面排除,避免跳转页面
问题发现:通过浏览器抓取网页工具我们发现网站中出现http请求404错误。
问题分析解决:HTTP请求时间消耗是很大的,因此使用HTTP请求来获得一个没有用处的响应(例如404没有找到页面)是完全没有必要的,它只会降低用户体验而不会有一点好处。经排查代码中下面代码造成了404:
修改正确后,时间变短,效果如下:
问题总结:HTTP请求应该保证不能出现404错误,同时尽量减少301和302跳转。
二、使用js压缩插件
问题发现:通过浏览器抓取网页工具我们发现网站中存在个文件4.5M,响应时间45豪秒。
问题分析解决:经排查我们发现此js插件有压缩文件,我们替换用压缩问题替换后效果如下:
同理我们发现了jquery-ui.js也没有使用压缩版插件。
问题总结:精简js,尽可能的使用第三方压缩版插件,去除代码不必要的字符(注释,空格、换行、tab缩进),可以减少文件大小从而节省下载时间。
三、尽量减少HTTP 请求
问题发现:终端用户响应的时间中,有80%用于下载各项内容。这部分时间包括下载页面中的图像、样式表、脚本、Flash等。通过减少页面中的元素可以减少 HTTP请求的次数。这是提高网页速度的关键步骤。
常见的方法:
1、 合并脚本跟样式文件,如可以把多个 CSS 文件合成一个,把多个 JS 文件合成一个。
2、 CSSSprites 利用 CSS background 相关元素进行背景图绝对定位,把多个图片合成一个图片。
问题分析解决:通过浏览器抓取网页工具我们发现网站中home.js和menu.js可以合并。
问题总结:减少http请求可以有效提供网页速度,开发中应注意尽可能少的减少请求。
四、使用get请求
问题发现:通过浏览器抓取网页工具我们发现网站中出现了post请求。
问题分析解决:当使用XMLHttpRequest时(非普通post请求),浏览器中的POST方法是一个“两步走”的过程:首先发送文件头,然后才发送数据。因此使用GET最为恰当,因为它只需发送一个TCP包(除非你有很多cookie)。IE中URL的最大长度为2K,因此如果你要发送一个超过2K的 数据时就不能使用GET了。
一个有趣的不同就是POST并不像GET那样实际发送数据。根据HTTP规范,GET意味着“获取”数据,因此当你仅仅获取数据时使用GET更加有意义(从语意上讲也是如此),相反,发送并在服务端保存数据时使用POST。
查看代码发现此http请求触发方式如下:
查看jQuery官网.load源码我们发现如下代码:
可以发现当prams为空时.load为get请求,prams不为空时post请求。
特此修改代码如下:
修改后的请求如下:
问题总结:从服务器上请求数据尽可能使用get,向服务器发送数据保存尽量使用post,post安全性高于get。
五、样式脚本位置调整
问题发现:网站性能优化的法则中有以下两点要注意:
一、将脚本放在底部
脚本放在顶部带来的问题:
1、 使用脚本时,对于位于脚本以下的内容,逐步呈现将被阻塞
2、 在下载脚本时会阻塞并行下载
放在底部可能会出现JS错误问题,当脚本没加载进来,用户就触发脚本事件。
二、将样式文件放在页面顶部
如果样式表任在加载,构建呈现树就是一种浪费,样式文件放在页面底部可能会出现两种情况:
1、 白屏
2、 无样式内容的闪烁
问题分析解决:调整home.jsp中js引用位置。
问题总结:开发中应尽量将脚本放在底部,将样式文件放在页面顶部。
六、使用浏览器缓存
问题发现:通过浏览器抓取网页工具我们发现网站中项目中一直出现200,无法缓存的现象。
问题分析解决:查找代码发现项目中有如下过滤器:
过滤器内容如下:
在此我们删除禁止缓存代码,启用缓存,效果如下:
问题总结:使用浏览器缓存能够有效的减少请求时间,网站js,css文件加载应该尽可能的使用缓存。
资料:http://www.ha97.com/2710.html
七、使用jQuery缓存
问题分析:通过浏览器抓取网页工具我们发现网站中easyloader.js后面一直有随机数,造成js重复加载。
问题分析解决:经排查此easyloader.js在多目录信息模板中应用,查找资料此现象是jQuery缓存机制造成的。我们在page.js中加入全局缓存设置:
加入后即可发现请求easyloader.js后不会再拼接时间戳。
问题总结:适当的使用jQuery全局缓存,可以减少http请求。
资料:http://blog.youkuaiyun.com/wuha555/article/details/41439797
http://blog.youkuaiyun.com/gkingzheng/article/details/11125491
第三章.程序的优化
一、去除httpclient请求
问题发现:loadrunner跑脚本性能时发现遇到网络瓶颈问题,看日志查看可以发现了个httpclient请求不停发送,另我们通过浏览器抓取网页工具也可以发现console网站请求响应时间过长。
问题分析解决:经排查代码发现打开网站(toWebsite)时,会在ThemeUtil中执行如下代码:
特此我们在此去除httpclient请求:
改用如下方式:
修改后效果如下:
问题总结:请求页面时,程序中尽可能的避免使用httpclient,这样有助于我们提高请求数据。
二、部件缓存使用
程序使用内存缓存机制可以缓存一些可以缓存的数据(例如需要经常查询数据库的数据,需要经常使用的数据),能够极大的提高代码执行效率,提升系统系能,ExPortal项目使用了ehcache缓存来缓存数据库查询数据,极大的减少了数据库查询压力,提升了系统性能,ehcache内存缓存机制在此不做详述,读者可以参考相关资料进行研究学习。
三、freemarker缓存使用
问题发现:通过浏览器抓取网页工具我们发现部件请求模板数据的时间很长,并无法缓存。
问题分析解决:部件请求模板数据以及改为get请求后请求数据还是很长(启用了jQuery缓存的前提下),在这里我们采用了freemarke缓存数据机制来缓存模板数据,在项目web.xml中我们将freemarke模板拦截器中NoCache设为false,即可使用freemarke缓存,
freemarke缓存结合jQuery缓存使用可以缓存掉该url请求。
增加缓存效果后,抓取网页结果如下:
问题总结:freemarke缓存能很好的减少http请求时间。
资料:http://www.tuicool.com/articles/7FBVZfn
四、日志调整
测试性能时,尽可能的减少日志输入,减少文件读写,可以提升系统性能。
第四章.服务器优化
服务器优化方面在此不做深入讲解.