项目背景

大客户吐槽,订单导出太慢,从开始到结束,可以看一部电影了。。。

分析原因

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分钟左右,比之前一个多小时,提升了不少

优化性能----百万订单导出相关推荐

  1. 支撑日均百万订单的微服务架构应该这么搞

    最近几年微服务很火,大家都在建设微服务,如果不懂点微服务相关的技术,都不好意思跟同行打招呼了. 我也见过身边很多人在微服务踩过很多坑,我从 2016 年开始接触微服务,有多家大型企业的微服务分布式系统 ...

  2. 前端不哭!最新优化性能经验分享来啦 | 技术头条

    作者 | Dimitris Kiriakakis 译者 | 风车云马 编辑 | Jane 出品 | Python大本营(id:pythonnews) [导语]Angular.React.VueJS 是 ...

  3. [转帖]ASP.NET中常用的优化性能的方法

    ASP.NET中常用的优化性能的方法(转贴,Icyer收集整理) 1.       数据库访问性能优化     数据库的连接和关闭 访问数据库资源需要创建连接.打开连接和关闭连接几个操作.这些过程需要 ...

  4. c mysql批量插入优化_MySQL实现批量插入以优化性能的教程

    这篇文章主要介绍了MySQL实现批量插入以优化性能的教程,文中给出了运行时间来表示性能优化后的对比,需要的朋友可以参考下 对于一些数据量较大的系统,数据库面临的问题除了查询效率低下,还有就是数据入库时 ...

  5. win7优化设置_win7优化性能的操作步骤

    作为目前市场占有率最高的电脑操作系统,win7系统无疑是成功的,最近不少用户问小编win7系统怎么才可以优化性能,其实方法很简单,下面就来看看我是怎么操作的. 不少刚安装好win7系统的用户觉得win ...

  6. 硬件加速下webview切换闪屏_网页渲染性能优化 —— 性能优化下

    博客 有更多精品文章哟. Composite 的优化 终于,我们到了像素管道的末尾.对于这一部分的优化策略,我们可以从为什么需要 Composited Layer(Graphics Layer)来入手 ...

  7. mysql如何优化性能优化_如何优化性能?MySQL实现批量插入以优化性能的实例详解...

    这篇文章主要介绍了MySQL实现批量插入以优化性能的教程,文中给出了运行时间来表示性能优化后的对比,需要的朋友可以参考下 对于一些数据量较大的系统,数据库面临的问题除了查询效率低下,还有就是数据入库时 ...

  8. 使用Lua 局部变量来优化性能,同一时候比較局部变量和全局变量

    在竞争激烈的游戏行业中,尤其页游,面对策划复杂和频繁的需求,使用脚本能够减少难度和成本.在使用Lua的过程中,会常常訪问全局变量来作为配置文件. 在訪问全局变量时,能够通过局部变量引用全局变量来优化. ...

  9. 订单导出(1688)

    目录 下载地址 功能列表 简要步骤 从应用列表中选择1688订单导出 点击进入后登录1688,进入买家订单列表 直接点击订单导出按钮,选择要导出的数据项 输入导出的Excel保存位置与名称 导出完毕后 ...

最新文章

  1. iscroll 滚动刷新
  2. javascript事件循环机制EventLoop
  3. ehlib中dbgrideh的多选框设置
  4. Windows内存管理 - 隐藏在new和malloc背后的heap
  5. WPF Slider设置整数
  6. 通过tomcat日志定位错误
  7. struts2的namespace的问题
  8. [置顶] 原创鼠标拖动实现DIV排序
  9. webrtc2sip项目说明
  10. zktime 协议_zktime5.0考勤管理系统使用说明书(1.2版).pdf
  11. 惠普136w墨粉量低_打印机墨粉量低怎么处理_打印机显示墨粉量低解决方法
  12. 软硬件全开源,航芯方案分享 | 热敏打印机方案
  13. python中floor_Python torch.floor方法代码示例
  14. 【读书笔记-诗词歌赋】诗词积累(一)
  15. 在ADSP-BF561上使用x264(4):确认热点
  16. 广发样样行这样做可以提额
  17. 关于Oracle数据库start whith 递归查询的另类认知
  18. MATLAB产生伪随机数
  19. catia 斑马线分析_在CATIA中使用斑马线检查曲面光顺性的方法 | 坐倚北风
  20. Linux下的Cannot find a valid baseurl for repo: base/7/x86_64问题记载

热门文章

  1. Android手机如何获取唯一标识(手机串号)
  2. 正好智投资讯指数高开高走
  3. 为什么亚马逊被认为是最有战略头脑的科技公司?
  4. 刷机精灵被腾讯6000万收购
  5. 算法-蓝桥杯习题(5-1)
  6. Go语言基础知识01-用Go打个招呼
  7. 如何用R语言参破每个复仇者的口头禅?
  8. grep命令常用用法示例
  9. SaaS餐饮管理软件有哪些优势?
  10. DFPlayer Mini单片机-让你的Arduino Uno会唱歌