java查询数据库百万条数据,优化之:多线程+数据库
短信预约 -IT技能 免费直播动态提醒
java百万查询语句优化
业务需求
今天去面试时hr问了个关于大量数据查询的问题。
面试官:“我们公司是做数据分析的,每次需要从数据库中查询100万条数据进行分析,不能用分页,请问怎么优化sql或者java代码呢??”
如果用普通查询需要5分多分钟才查询完毕,所以我们用索引加多线程来实现。
那我们就开始吧!GO!!GO!!
数据库设计
编写数据库字段
然后要生成100万条数据
在数据库添加索引
索引这个方面我还是不太了解,大家懂的可以优化索引
代码实现
java编写
controller类编写
package com.neu.controller; import com.neu.mapper.UserMapper;import com.neu.pojo.User;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;import javax.annotation.Resource;import java.util.*;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; @Controllerpublic class ExecutorUtils { @Resource private UserMapper userMapper; // 一个线程最大处理数据量 private static final int THREAD_COUNT_SIZE = 5000; @RequestMapping("Executor") public List executeThreadPool() { //计算表总数 Integer integer = userMapper.UserSum(); //记录开始时间 long start = System.currentTimeMillis(); //new个和表总数一样长的ArrayList List threadList=new ArrayList<>(integer); // 线程数,以5000条数据为一个线程,总数据大小除以5000,再加1 int round = integer / THREAD_COUNT_SIZE + 1; //new一个临时储存List的Map,以线程名为k,用做list排序 Map temporaryMap = new HashMap<>(round); // 程序计数器 final CountDownLatch count = new CountDownLatch(round); // 创建线程 ExecutorService executor = Executors.newFixedThreadPool(round); // 分配数据 for (int i = 0; i < round; i++) { //该线程的查询开始值 int startLen = i * THREAD_COUNT_SIZE; int k = i + 1; executor.execute(new Runnable() { @Override public void run() { ArrayList users = userMapper.subList(startLen); //把查出来的List放进临时Map temporaryMap.put(k,users); System.out.println("正在处理线程【" + k + "】的数据,数据大小为:" + users.size()); // 计数器 -1(唤醒阻塞线程) count.countDown(); } }); } try { // 阻塞线程(主线程等待所有子线程 一起执行业务) count.await(); //结束时间 long end = System.currentTimeMillis(); System.out.println("100万数据查询耗时:" + (end - start) + "ms"); //通过循环遍历临时map,把map的值有序的放进List里 temporaryMap.keySet().forEach(k->{ threadList.addAll(temporaryMap.get(k)); }); } catch (Exception e) { e.printStackTrace(); } finally { //清除临时map,释放内存 temporaryMap.clear(); // 终止线程池 // 启动一次顺序关闭,执行以前提交的任务,但不接受新任务。若已经关闭,则调用没有其他作用。 executor.shutdown(); } //输出list的长度 System.out.println("list长度为:"+threadList.size()); return threadList; }}
编写Mapper
package com.neu.mapper;import java.util.ArrayList;import java.util.List;import org.apache.ibatis.annotations.*;import com.neu.pojo.User;@Mapperpublic interface UserMapper { @Select("SELECT count(*) as sum FROM sysuser")Integer UserSum(); @Select("select * from sysuser LIMIT #{startLen},5000")ArrayList subList(@Param("startLen") int startLen);}
编写完成后我们测试一波–>
测试结果20秒内,比之前快了好多
模糊查询
模糊查询呢?
咱测试一下:
修改Mapper
package com.neu.mapper;import java.util.ArrayList;import java.util.List;import org.apache.ibatis.annotations.*;import com.neu.pojo.User;@Mapperpublic interface UserMapper { @Select("SELECT count(*) as sum FROM sysuser where id like concat('%',0,'%')")Integer UserSum(); @Select("select * from sysuser where id like concat('%',0,'%') LIMIT #{startLen},5000")ArrayList subList(@Param("startLen") int startLen);}
修改完成后我们再测试一波–>
耗时5秒左右,可以满足业务需求
结束
目前基本的查询已经写完
看到这个文章的还可以对以下方面进行优化:
- 索引进行优化。
- 每个线程查询多少条数据最为合适??
- 如果配置有线程池可以使用:总条数/线程数==每个线程需要查询多少条数据。
- 进行代码优化,优化一些耗时的代码。
来源地址:https://blog.csdn.net/m0_57647880/article/details/131064291
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341