• 性能优化——算法优化


    背景

    由于某种原因,我们系统需要记录另一个系统中一个表里的id但是,当我们记录完了以后,别人系统可能会删除那个表里的一些数据,这样的话,我们这边就多了一些无效数据,所以,我们必须的找到这些无效的id,然后将其删除。

     

    开始,我们的实现是这样:我们将记录下来的所有id放在一个list里,然后传到另一个系统,他将他们已经删除的id返回。具体处理代码如下:

    1. <pre name="code" class="java">public String findDeletedStuChooseCourseIds(List<String> stuChooseCourseIds) {  
    2.     List<String> delIds = new ArrayList<String>();  
    3.     // 循环遍历所有给定id,查看是否存在  
    4.     for (String id : stuChooseCourseIds) {  
    5.         StuChooseCourse stuChooseCourse = commonEao.get(StuChooseCourse.class, id);  
    6.         if (null == stuChooseCourse) {  
    7.             delIds.add(id);  
    8.         }  
    9.     }  
    10.     return JsonUtils.toJson(delIds);  
    11. }  


    开始的时候,数据量比较小,并没有感觉到这个方法有什么问题。但是随着时间的推移,数据量不断增加,最终达到十几万条数据,问题也就随之而来了。这个方法的执行时间已经远远超出了我们的忍耐极限,竟然5分钟都没有执行完,这个必须得优化。

    分析一下执行慢的原因,很明显,循环里的查找数据费了时间,每循环一次,都需要去数据库中查找一次,这样能快就见鬼了。所以,必须减少与数据库的交互。于是代码变成了如下版本:

    1. <pre name="code" class="java">public String findDeletedStuChooseCourseIds(List<String> stuChooseCourseIds) {  
    2.     //获取所有stuchoosecourse的ids  
    3.     String  nativeSql = "select id from tableName ";  
    4.     List<String> list = commonEao.executeGetNativeSQL(nativeSql);  
    5.       
    6.     stuChooseCourseIds.removeAll( list );  
    7.       
    8.     return JsonUtils.toJson(stuChooseCourseIds);  
    9. }  


    这样的话,只需要跟数据库进行一次交互,而且使用的jdk的removeAll方法(一般jdk实现的方法,效率都还不错),效率应该会提高不少。于是,我满怀希望的进行测试,但结果还是让人难以接受,效率似乎并没有提高多少。

    分析一下原因,肯定是stuChooseCourseIds.removeAll(list )浪费了时间,因为我们使用的listarrayList,而arrayList在执行查找和删除操作时是比较费时间的。后来,我们换成了LinkedList,但结果还是一样。所以,我们必须换种思维方式了。于是,代码变成了如下版本:

    1. <pre name="code" class="java">public String findDeletedStuChooseCourseIds(List<String> stuChooseCourseIds) {  
    2.     List<String> delIds = new ArrayList<String>();  
    3.     //获取所有stuchoosecourse的ids  
    4.     String  nativeSql = "select id from tableName ";  
    5.     List<String> list = commonEao.executeGetNativeSQL(nativeSql);  
    6.     //将list中的id放到HashSet中  
    7.     HashSet<String> dbSet = new HashSet<String>();  
    8.     for(String id : list){  
    9.         dbSet.add(id);  
    10.     }  
    11.       
    12.     //将stuChooseCourseIds中的id放到dbSet中  
    13.     for(String givenId : stuChooseCourseIds){  
    14.         if(dbSet.add(givenId)){  
    15.             delIds.add(givenId);  
    16.         }  
    17.     }  
    18.       
    19.     return JsonUtils.toJson(delIds);  
    20. }  



    这里使用HashSet来处理。首先,一旦用到Hash,查找效率定然会大幅度提升。其次,巧妙的利用了Set中元素不可重复的特性。这样一来,最终的执行效率提升了20多倍,原本五分钟都结束不了的方法,现在仅需要十几秒。这个结果还是让人比较满意的。

     

    数据量小的时候,问题不明显,等数据量多了以后,问题出来了。这个问题也告诉我们,凡事都要用发展的眼光看问题。既然如此,那么让我们继续看最后一版的代码。

     

    现在数据量是十几万,如果时间再向后推移,数据量变成百万,试想将百万的数据放在一个list里,暂且不说效率的问题,请问你的内存受得了吗?答案是肯定的,内存会被撑爆。那么,这个问题必须解决。于是,最终的版本如下:

    1. <pre name="code" class="java">public String findDeletedStuChooseCourseIds(List<String> stuChooseCourseIds,String schoolCalendarId) {  
    2.     List<String> delIds = new ArrayList<String>();  
    3.     //获取所有stuchoosecourse的ids  
    4.     String  nativeSql = "select id from tableName where schoolcalendarid='"+schoolCalendarId+"'";  
    5.     List<String> list = commonEao.executeGetNativeSQL(nativeSql);  
    6.     //将list中的id放到HashSet中  
    7.     HashSet<String> dbSet = new HashSet<String>();  
    8.     for(String id : list){  
    9.         dbSet.add(id);  
    10.     }  
    11.       
    12.     //将stuChooseCourseIds中的id放到dbSet中  
    13.     for(String givenId : stuChooseCourseIds){  
    14.         if(dbSet.add(givenId)){  
    15.             delIds.add(givenId);  
    16.         }  
    17.     }  
    18.       
    19.     return JsonUtils.toJson(delIds);  
    20. }  



    方法又加了一个参数——学年学期,每一学期产生的数据基本上是不变的,这样一来,无论多久之后,方法的执行效率都不会再受影响。

     

    通过这次的优化,让我真正感受到了数据结构的魅力。骚年,有时间好好学习一下数据结构吧!

  • 相关阅读:
    UOJ.26.[IOI2014]Game(交互 思路)
    Good Bye 2016 F.New Year and Finding Roots(交互)
    Codeforces.835E.The penguin's game(交互 按位统计 二分)
    Codeforces.744B.Hongcow's Game(交互 按位统计)
    Codeforces.862D.Mahmoud and Ehab and the binary string(交互 二分)
    正睿OI 提高 Day1T3 ZYB玩字符串(DP)
    划分vlan
    2三层交换机实现vlan间的路由
    交换机基础-交换机远程telnet
    自动化运维环境的搭建问题处理
  • 原文地址:https://www.cnblogs.com/fengyv/p/3788304.html
Copyright © 2020-2023  润新知