优化性能----百万订单导出
项目背景
大客户吐槽,订单导出太慢,从开始到结束,可以看一部电影了。。。
分析原因
1.产品设计上无导出时间区间限制
2.导出字段太繁琐,大概有120个字段,关联表20张左右
3.自定义导出字段,后台没有判断,还是走全字段导出逻辑
4.没有适当冗余字段
5.单线程执行
优化方案
文本产品设计上改变不了,冗余字段的没办法实现,因为是订单表,改表结构,风险太大,还是在原有的代码上优化吧,只说大概思路,具体代码因为是公司项目,不方便贴出来,贴些伪代码 数据量最大导出100万
1.先死循环,使用滚动翻页查询订单主表,取消LIMIT offset,size的效率太低,因为此方案每次查询都是最终的结果集,而一般的分页方案使用的LIMIT offset,size需要先查询,后截断,查询的数据放到队列中
2.线程池处理队列数据,主要是组装不在订单表的字段数据,组装好之后把数据放到另一个队列,业务中用到并行流,处理订单列表,用","拼接订单id,判断要导出的字段有哪些, 根据导出的字段,用拼接订单id为条件批量查询需要导出字段的列表数据,结果集,再依订单id分组,使用map保存,方便给原数据对比,这样做节省了每次循环查询对应字段的数据
3.死循环监听组装好的队列数据,拿到数据之后调用EasyExcel写数据
第一步伪代码
//起始idLong lastBatchMaxId = 0L;//每页大小Integer pageSize = 2000;map.put("lastBatchMaxId", lastBatchMaxId);map.put("pageSize", pageSize);// 数据库查询的结果集 待处理数据BlockingQueue<List<OrderExcelData>> queue = new ArrayBlockingQueue<>(500);//组装好的数据的队列BlockingQueue<List<OrderExcelData>> queue1 = new ArrayBlockingQueue<>(500);for (; ; ) {List<OrderExcelData> collect1 = orderDao.selectOrderExcelDataByMap(map);//为空结束循环if (CollectionUtils.isEmpty(collect1)) {break;}//待处理数据入队queue.put(collect1);//下次循环起始id 一般都是结果集 主键id最大的值lastBatchMaxId = collect1.stream().map(OrderExcelData::getOrderId).max(Long::compareTo).orElse(Long.MAX_VALUE);map.put("lastBatchMaxId", lastBatchMaxId);
使用此方法需要数据库主键是自增,lastBatchMaxId起始id,size每次取多少数据
第二步伪代码
//创建线程池 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(6, 6, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(500));int size = queue.size();for (int a = 0; a < size ; a++) {threadPoolExecutor.submit(new Runnable() {@Overridepublic void run() {try {//待处理数据List<OrderExcelData> list = queue.take();//组装数据batchAssemblyData(list,includeColumnFiledNames);//组装好把数据入队queue1.put(list);} catch (Exception e) {log.error("多线程组装数据错误{}", e);}}});}void batchAssemblyData(List<OrderExcelData> orderExcelDataList, Set<String> export) {//用","拼接订单idString collect = orderExcelDataList.stream().map(a -> String.valueOf(a.getOrderId())).collect(Collectors.joining(","));//运费险相关 先判断导出 是否有运费相关字段 有就批量把当前任务订单运费险相关的数据查到,再用订单id分组保存 这里只写一种 实际有30多个字段需要这样查出来Map<Long, List<OrderExtryEntity>> orderExtryEntityGroups = null;if (export.contains("freightInsurance")) {orderExtryEntityGroups = orderExtryDao.selectList(new EntityWrapper<OrderExtryEntity>().in("order_id", collect).eq("`key`", "freight_insurance")).stream().collect(Collectors.groupingBy(OrderExtryEntity::getOrderId));}//并行组装数据 实际项目中 有订单明细表 订单给明细是一对的关系,有些字段是给明细一对一的关系 需要做些特殊处理orderExcelDataList.parallelStream().forEach(a -> {//运费险相关if (orderExtryEntityGroups !=null && orderExtryEntityGroups .containsKey(a.getOrderId())) {for (OrderExtryEntity b : finalOrderExtryEntityGroups.get(a.getOrderId())) {a.setFreightInsurance(b.getValue());break;}}}}
网上说平行流处理速度比for循环慢,这个要是看场景的,只是遍历数据,没有io操作,数据量不大,确实平行流慢,我现在这个场景,也是要查数据库,并行流还是比for循环快的多的
第三步伪代码
//使用EasyExcel阿里的导出依赖ExcelWriter excelWriter = EasyExcel.write(fileName, OrderExcelData.class).includeColumnFiledNames(includeColumnFiledNames).build();WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build();//执行以前提交的任务,但不接受新任务threadPoolExecutor.shutdown();int a = 0;while (true) {List<OrderExcelData> take = queue1.poll(10, TimeUnit.SECONDS);if (take == null && threadPoolExecutor.isTerminated()) {log.info("所有的子线程都结束了");a++;}if (take != null) {//单线程写 多线程写又可能会损坏文件excelWriter.write(take, writeSheet);log.info("写数据" + take.size());}//检查2次 防止线程刚好结束 队列是空null值得时候if (a == 2) {break;}}
监听队列的好处是,线程处理好数据之后,马上写到文件中,节省了写文件的效率
优化结果
订单表大概有一千万数据 ,服务器配置4c—4g,导出某个月的数据量,订单90多万,120个字段全部导出,耗时15分钟左右,比之前一个多小时,提升了不少
优化性能----百万订单导出相关推荐
- 支撑日均百万订单的微服务架构应该这么搞
最近几年微服务很火,大家都在建设微服务,如果不懂点微服务相关的技术,都不好意思跟同行打招呼了. 我也见过身边很多人在微服务踩过很多坑,我从 2016 年开始接触微服务,有多家大型企业的微服务分布式系统 ...
- 前端不哭!最新优化性能经验分享来啦 | 技术头条
作者 | Dimitris Kiriakakis 译者 | 风车云马 编辑 | Jane 出品 | Python大本营(id:pythonnews) [导语]Angular.React.VueJS 是 ...
- [转帖]ASP.NET中常用的优化性能的方法
ASP.NET中常用的优化性能的方法(转贴,Icyer收集整理) 1. 数据库访问性能优化 数据库的连接和关闭 访问数据库资源需要创建连接.打开连接和关闭连接几个操作.这些过程需要 ...
- c mysql批量插入优化_MySQL实现批量插入以优化性能的教程
这篇文章主要介绍了MySQL实现批量插入以优化性能的教程,文中给出了运行时间来表示性能优化后的对比,需要的朋友可以参考下 对于一些数据量较大的系统,数据库面临的问题除了查询效率低下,还有就是数据入库时 ...
- win7优化设置_win7优化性能的操作步骤
作为目前市场占有率最高的电脑操作系统,win7系统无疑是成功的,最近不少用户问小编win7系统怎么才可以优化性能,其实方法很简单,下面就来看看我是怎么操作的. 不少刚安装好win7系统的用户觉得win ...
- 硬件加速下webview切换闪屏_网页渲染性能优化 —— 性能优化下
博客 有更多精品文章哟. Composite 的优化 终于,我们到了像素管道的末尾.对于这一部分的优化策略,我们可以从为什么需要 Composited Layer(Graphics Layer)来入手 ...
- mysql如何优化性能优化_如何优化性能?MySQL实现批量插入以优化性能的实例详解...
这篇文章主要介绍了MySQL实现批量插入以优化性能的教程,文中给出了运行时间来表示性能优化后的对比,需要的朋友可以参考下 对于一些数据量较大的系统,数据库面临的问题除了查询效率低下,还有就是数据入库时 ...
- 使用Lua 局部变量来优化性能,同一时候比較局部变量和全局变量
在竞争激烈的游戏行业中,尤其页游,面对策划复杂和频繁的需求,使用脚本能够减少难度和成本.在使用Lua的过程中,会常常訪问全局变量来作为配置文件. 在訪问全局变量时,能够通过局部变量引用全局变量来优化. ...
- 订单导出(1688)
目录 下载地址 功能列表 简要步骤 从应用列表中选择1688订单导出 点击进入后登录1688,进入买家订单列表 直接点击订单导出按钮,选择要导出的数据项 输入导出的Excel保存位置与名称 导出完毕后 ...
最新文章
- iscroll 滚动刷新
- javascript事件循环机制EventLoop
- ehlib中dbgrideh的多选框设置
- Windows内存管理 - 隐藏在new和malloc背后的heap
- WPF Slider设置整数
- 通过tomcat日志定位错误
- struts2的namespace的问题
- [置顶] 原创鼠标拖动实现DIV排序
- webrtc2sip项目说明
- zktime 协议_zktime5.0考勤管理系统使用说明书(1.2版).pdf
- 惠普136w墨粉量低_打印机墨粉量低怎么处理_打印机显示墨粉量低解决方法
- 软硬件全开源,航芯方案分享 | 热敏打印机方案
- python中floor_Python torch.floor方法代码示例
- 【读书笔记-诗词歌赋】诗词积累(一)
- 在ADSP-BF561上使用x264(4):确认热点
- 广发样样行这样做可以提额
- 关于Oracle数据库start whith 递归查询的另类认知
- MATLAB产生伪随机数
- catia 斑马线分析_在CATIA中使用斑马线检查曲面光顺性的方法 | 坐倚北风
- Linux下的Cannot find a valid baseurl for repo: base/7/x86_64问题记载