惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

腾讯CDC
Hacker News: Ask HN
Hacker News: Ask HN
S
Securelist
Security Latest
Security Latest
S
Schneier on Security
T
Threat Research - Cisco Blogs
Latest news
Latest news
Cyberwarzone
Cyberwarzone
A
Arctic Wolf
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
NISL@THU
NISL@THU
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
I
Intezer
T
The Exploit Database - CXSecurity.com
N
News and Events Feed by Topic
Simon Willison's Weblog
Simon Willison's Weblog
T
Tor Project blog
Blog — PlanetScale
Blog — PlanetScale
C
Cyber Attacks, Cyber Crime and Cyber Security
C
CERT Recently Published Vulnerability Notes
The Hacker News
The Hacker News
月光博客
月光博客
WordPress大学
WordPress大学
博客园 - 叶小钗
Hugging Face - Blog
Hugging Face - Blog
美团技术团队
量子位
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cisco Blogs
博客园 - 三生石上(FineUI控件)
Google DeepMind News
Google DeepMind News
Project Zero
Project Zero
Webroot Blog
Webroot Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Application and Cybersecurity Blog
Application and Cybersecurity Blog
云风的 BLOG
云风的 BLOG
L
LINUX DO - 最新话题
Schneier on Security
Schneier on Security
Engineering at Meta
Engineering at Meta
www.infosecurity-magazine.com
www.infosecurity-magazine.com
aimingoo的专栏
aimingoo的专栏
D
Docker
有赞技术团队
有赞技术团队
Google DeepMind News
Google DeepMind News
宝玉的分享
宝玉的分享
T
Troy Hunt's Blog
L
Lohrmann on Cybersecurity
T
The Blog of Author Tim Ferriss
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
L
LangChain Blog

博客园 - fengyv

塑造职场影响力的五大法宝 怎样培养独挡一面的能力 数据结构 - 归并排序(merging sort) [分享]恼人的设计模式 Git使用总结 设计师整理的系统开发流程-简洁又有重点 JavaScript中的String对象 python高效解析日志入库 如何让js不产生冲突,避免全局变量的泛滥,合理运用命名空间 HTML CSS——margin和padding的学习 三层浅析及示例分析 C语言的代码内存布局详解 超级立方体小记 如何和项目经理沟通产品的交付? CentOS配置smaba与Windows共享文件 Javascript实现简单的下拉二级菜单 从测试员到测试负责人 项目团队中4种组员类型的相应管理方式 在软件项目管理中如何把时间估算的靠近真实值?
性能优化——算法优化
fengyv · 2014-06-14 · via 博客园 - fengyv

背景

由于某种原因,我们系统需要记录另一个系统中一个表里的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.       
  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.       
  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.       
  4.     String  nativeSql = "select id from tableName ";  
  5.     List<String> list = commonEao.executeGetNativeSQL(nativeSql);  
  6.       
  7.     HashSet<String> dbSet = new HashSet<String>();  
  8.     for(String id : list){  
  9.         dbSet.add(id);  
  10.     }  
  11.       
  12.       
  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.       
  4.     String  nativeSql = "select id from tableName where schoolcalendarid='"+schoolCalendarId+"'";  
  5.     List<String> list = commonEao.executeGetNativeSQL(nativeSql);  
  6.       
  7.     HashSet<String> dbSet = new HashSet<String>();  
  8.     for(String id : list){  
  9.         dbSet.add(id);  
  10.     }  
  11.       
  12.       
  13.     for(String givenId : stuChooseCourseIds){  
  14.         if(dbSet.add(givenId)){  
  15.             delIds.add(givenId);  
  16.         }  
  17.     }  
  18.       
  19.     return JsonUtils.toJson(delIds);  
  20. }  

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

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