网站首页 > 技术文章 正文
现在有一个需求,我会从两个不同的服务器获取到两个数组A和B,两个数组都是相同的对象格式,其中包含一个相同的主键ID。我们要将数组A和B进行比较,假设A是主数组,B是新数组。然后执行操作:
1、A的一个ID在B里不存在,执行delete()方法。
2、B数组中的一个ID在A数组里不存在,执行add()方法。
3、B数组中的一个ID在A数组中存在,但是内容不同,则执行update()方法。
首先,我想到使用HashSet集合存储数据,然后轮询遍历,根据之前项目的需求量,设置A为8000条数据,B为8010条数据,通过循环赋值到一个Set中。A数组起名为oldList,B数组起名为newList然后对性能进行计时计算,代码如下
- public class Test1 {
- public static void main(String[] args) {
- Set<Client> oldList = new HashSet<Client>();
- Set<Client> newList = new HashSet<Client>();
- int updateNum = 0;
- int addNum = 0;
- for (int i = 0; i < 8000; i++) {
- oldList.add(new Client(i+"", "客户"+i, "地址"+i, "CID"+i));
- }
- for (int i = 0; i < 8010; i++) {
- if(i%179==0) {
- newList.add(new Client("", "客户信息"+i, "地址信息"+i, "CID"+i));
- }else {
- newList.add(new Client(i+"", "客户"+i, "地址"+i, "CID"+i));
- }
- }
- long start = new Date().getTime();
- long initTime = new Date().getTime();
- System.out.println("初始化时间:"+(initTime-start));
- for(Client newC:newList) {
- boolean newhas = false;
- for(Client oldC:oldList) {
- if(newC.getClientId().equals(oldC.getClientId())) {
- newhas = true;
- if(oldC.getAddress().equals(newC.getAddress()) && oldC.getName().equals(newC.getName())) {
- break;
- }else {
- updateNum++;
- update();
- }
- }
- }
- if(!newhas) {
- //oldList.add(new Client((oldList.size()+1)+"", newC.getName(), newC.getAddress(), newC.getClientId()));
- addNum++;
- add();
- }
- }
- long end = new Date().getTime();
- System.out.println("总共用时:"+(end-start)+"ms,执行用时:"+(end-initTime)+"ms,新增了:"+addNum+"条,修改了:"+updateNum+"条");
- }
- public static void update() {
- }
- public static void add() {
- }
- }
第一次执行:
初始化时间:0
总共用时:884ms,执行用时:884ms,新增了:10条,修改了:45条
第二次执行:
初始化时间:0
总共用时:905ms,执行用时:905ms,新增了:10条,修改了:45条
第三次执行:
初始化时间:0
总共用时:871ms,执行用时:871ms,新增了:10条,修改了:45条
其中for循环往Set中存数据的过程不在计时的时间内。可以看到,8000条数据需要将近1秒的时间遍历出来,从现阶段可能还算够用,但是长久考虑,数据量越来越大(往后可能百万级),这个肯定不行。我们试一下2W条数据:
初始化时间:0
总共用时:11082ms,执行用时:11082ms,新增了:0条,修改了:112条
实在是长的不行。然后我就分析到底是哪里导致性能这么差,我想是因为多次无意义的循环导致的吧。然后我突然想起了Map集合可以判断key是否存在,那我把主键ID存入key中,value做为这个对象,来使用呢?然后完成如下代码:
- public class Test3 {
- public static void main(String[] args) {
- Set<Client> oldList = new HashSet<Client>();
- Set<Client> newList = new HashSet<Client>();
- int updateNum = 0;
- int addNum = 0;
- int deleteNum = 0;
- for (int i = 0; i < 8000; i++) {
- Client client = new Client(i+"", "客户"+i, "地址"+i, "CID"+i);
- oldList.add(client);
- }
- for (int i = 0; i < 8010; i++) {
- if(i%5657==0) {
- Client client = new Client("", "客户信息"+i, "地址信息"+i, "CID"+i);
- newList.add(client);
- }else if(i%9973==0){
- continue;
- }else {
- Client client = new Client(i+"", "客户"+i, "地址"+i, "CID"+i);
- newList.add(client);
- }
- }
- long start = new Date().getTime();
- Map<String,Client> newMap = new HashMap<String,Client>();
- Map<String,Client> oldMap = new HashMap<String,Client>();
- for (Client n : newList) {
- newMap.put(n.getClientId(), n);
- }
- for (Client n : oldList) {
- oldMap.put(n.getClientId(), n);
- }
- long initTime = new Date().getTime();
- System.out.println("初始化时间:"+(initTime-start)+"ms");
- Set<String> newKey = newMap.keySet();
- Set<String> oldKey = oldMap.keySet();
- for (String key : newKey) {
- if(oldMap.containsKey(key)) {
- Client o = oldMap.get(key);
- Client n = newMap.get(key);
- if(!(o.getAddress().equals(n.getAddress()) && o.getName().equals(n.getName()))) {
- updateNum++;
- update();
- }
- }else {
- addNum++;
- add();
- }
- }
- long addUpdateTime = new Date().getTime();
- System.out.println("新增和修改时间:"+(addUpdateTime-initTime)+"ms");
- for (String key : oldKey) {
- if(!newMap.containsKey(key)) {
- deleteNum++;
- delete();
- }
- }
- long end = new Date().getTime();
- System.out.println("删除时间:"+(end-addUpdateTime)+"ms");
- System.out.println("总共用时:"+(end-start)+"ms,新增了:"+addNum+"条,修改了:"+updateNum+"条,删除了:"+deleteNum+"条");
- }
- public static void add() {
- }
- public static void update() {
- }
- public static void delete() {
- }
- }
这套代码不仅实现了新增修改,还实现了删除功能,那么效率如何呢?
第一次运行:(初始化时间为把Set存入Map的时间,没有删除是因为设置的需要删除的素数较大,8000条中并不存在)
初始化时间:10ms
新增和修改时间:9ms
删除时间:3ms
总共用时:22ms,新增了:10条,修改了:2条,删除了:0条
第二次运行:
初始化时间:18ms
新增和修改时间:9ms
删除时间:3ms
总共用时:30ms,新增了:10条,修改了:2条,删除了:0条
第三次运行:
初始化时间:9ms
新增和修改时间:9ms
删除时间:3ms
总共用时:21ms,新增了:10条,修改了:2条,删除了:0条
可以看出来,这套代码的性能非常高,支撑8000条数据毫无压力,那么再多了呢?
1W条数据:
初始化时间:10ms
新增和修改时间:9ms
删除时间:4ms
总共用时:23ms,新增了:10条,修改了:2条,删除了:1条
5W条数据:
初始化时间:31ms
新增和修改时间:32ms
删除时间:15ms
总共用时:78ms,新增了:10条,修改了:9条,删除了:5条
30W条数据:
初始化时间:162ms
新增和修改时间:161ms
删除时间:78ms
总共用时:401ms,新增了:10条,修改了:54条,删除了:30条
50W条数据:
初始化时间:315ms
新增和修改时间:258ms
删除时间:128ms
总共用时:701ms,新增了:10条,修改了:89条,删除了:50条
一直到50W条数据,速度都比第一种方法的8000条数据要快,其中初始化就占用的将近一半的时间。最后我试一下百万条数据的速度如何:
初始化时间:611ms
新增和修改时间:548ms
删除时间:296ms
总共用时:1455ms,新增了:10条,修改了:177条,删除了:100条
百万条数据,大约只需要一秒半的时间就可以解决。感觉速度是真的快到不行!虽然我相信这肯定不是最优写法,但是感觉目前的业务需求量来讲,已经完全足够了。
那么在什么情况下,用第一种方法呢?我测试了一下,100条数据以内,你想用哪个用哪个,速度都是差不多的了。但是100条以上的,后者效率都要比前者快。
最后所以下遇到的神奇的情况,就是在数据量为25W~27.3W的区间里,效率会明显降低,全都需要1秒钟以上的响应时间,但是一到27.4W又恢复正常了。研究白天,百度很久,也没有发现问题所在。不过1秒钟的速度也还是可以接受了,所以暂时就先不考虑优化问题了。
这是我第一次对算法进行简单的优化,感觉是一件很有意思的事情。不知道这种结构是否能优化到百万级数据也在一秒以内查询出来?如果有大神看到这篇文章,帮忙分享一下呀,谢谢!
猜你喜欢
- 2024-09-20 非常详细!如何理解表格存储的多版本、生命周期和有效版本偏差
- 2024-09-20 6种快速统计代码执行时间的方法,真香
- 2024-09-20 Java 开发者最困惑的四件事(java开发遇到问题如何解决)
- 2024-09-20 【Java多线程】定时器Timer(java定时器线程池)
- 2024-09-20 还在用new Date计算任务执行时间?强烈建议使用这个API
- 2024-09-20 “抄”代码,再也不用上谷歌复制粘贴了
- 2024-09-20 java获取当前时间的四种方法代码实例
- 2024-09-20 撸完这篇线程池,我快咳血了(线程池有什么用)
- 2024-09-20 蒙圈了?System.currentTimeMillis()存在性能问题
- 2024-09-20 .NET 9 中的 Task.WhenEach(.net task thread)
- 1514℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 563℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 508℃MySQL service启动脚本浅析(r12笔记第59天)
- 486℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 485℃启用MySQL查询缓存(mysql8.0查询缓存)
- 465℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 445℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 442℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)