做系统优化两个多月了,优化了几个数据导出的功能,根据测试的结果来看,优化的效果还是很明显的,执行百秒以上的功能优化到了十秒之内,甚至有一个导出csv文件的给优化到了三秒内,所以一些优化经验还是可以借鉴的,下面我就针对我做优化的系统说一下我做的优化点,希望也能给和我一样的优化人员一些参考的价值。
要想解决问题首先得发现问题,第一步要做的就是熟悉整个功能的每个环节,可以用断点调试的方式跟一遍,然后添加日志打印方法和一些循环以及操作数据库的方法的执行时间,分析得出导致整体速度变慢的瓶颈位置,找出几个作为可以优化点的重点分析。
我优化的功能里主要有下面几个地方我觉得可以作为重点优化的点:
1、服务器缓存中数据查出来往客户端传输的过程(两万条数据从服务器到客户端用时三十秒)。
2、嵌套循环导出数据到excel工作簿中(两万条数据循环导出用时四秒多)。
3、改变每条数据的个别字段的属性名(循环两万条数据需要七秒)。
4、sql根据条件计数查询数据库(两百万条数据中查询计数两万条数据用时六十多秒)。
找出优化点就可以针对这些优化点重点分析,想办法改变它们的实现方法或者适当的添加一些条件来提高其执行效率,针对上面的四点我做出的优化方案如下:
1、针对服务器返回结果集到客户端耗去了大部分的时间,又考虑到服务器的性能可以承受的情况下,我将客户端导出文件移到了服务器来完成,客户端发出导出的命令,服务器执行导出文件到一个服务器端指定的文件夹后返回客户端一个下载地址,客户端下载导出的问题即可,这样局域网的下载速度很快,可以减少几十秒的数据传输时间。
2、减少循环变量的实例化,其性能也会提高,测试20000条数据的导出过程比原方法减少一秒的时间。代码如下:
原方法:
for (int i = 0; i < subList.size(); i ++) { GenericDO dto = subList.get(i); if (labels != null && labels.size() > 0) { for (int j = 0; j < labels.size(); j++) { Label2Property label2Property = (Label2Property) labels.get(j); … …
改为:
int i, j; int lSize = labels.size(); int sSize = subList.size(); GenericDO dto = null; Label2Property label2Property = null; String properyName = ""; for (i = 0; i < sSize; i ++) { dto = subList.get(i); if (labels != null && lSize > 0) { for (j = 0; j < lSize; j++) { label2Property = (Label2Property) labels.get(j); … …
3、原方案: 因为数据库里字段和界面显示table表头字段的命名有被改过的,比如:数据库表里的字段DURING_TIME对应界面表头里的字段是DURING_TIME_NAME,而在导出excel的时候,是通过读取界面表头里的字段去获取对应数据库里查出来了字段对应的数据,为了保证获取到数据,之前的做法是把从缓存中查出来的一条条数据进行了遍历,通过setPropertyNames(…)方法把变化了的修改为和界面表头里的字段命名一样,这样数据量大的情况下就会耗去了大量的时间,做了很多重复性的工作。
新方案:为了提高性能采取不再遍历查出来的数据,而是改变界面表头读取出来的字段值,因为表头只有几十个字段,读取出来放在list里传到服务器使用,在传递之前先设置改变字段值,即使遍历一遍也非常快,不影响整体的导出速度。
4、因为数据表里的条件字段没有索引,根据条件计数查询的时候是全表查询,所以很慢。给数据库表里的查询条件字段添加索引,条件时间字段加上索引后查询时间缩短到一秒内(这时还需要考虑一张表里索引数量,一张表里不易有过多的索引)。
在保证程序健壮稳定的前提下,让实现代码尽可能简单;嵌套循环尽可能少用,用的时候也需要遵循一定的原则,遵循循环次数多的放在外层,还有减少定义对象的次数;遵循面向对象的原则,各种功能都会有很多种实现方案,我们也要尽可能多试几种方案,找出更加合适的来使用。