线上订单数据导出功能优化历程分析和演示

背景:

订单导出功能,因公司业务需要,订单导出的字段,需要关联15张表

优化历程:

问题1:一开始用poi,出现过线上内存溢出的问题,

解决问题1:后通过加大内存,改用占用内存量小的工具easypoi,后来没出现过内存溢出问题。

问题2.:导出一个3000条数据的excel,经常超时。导致excel无法正常下载。

解决问题 2:原因是导出耗时比较久,出现超时的情况,这个时候把导出功能 迁移出去,在一个单独的 项目中去处理,处理完后,将生成的excel文件放到七牛云,让用户再去下载。

问题3:导出功能迁移到单独项目后,导出一个3000条数据的excel,居然需要30分钟!!!!

这里就详细说明目前处理方案和思路:

导出excel的字段,需要关联15张表才能完成产品的需求。

方案1,优化索引

关联15张表,改建的索引都建了,还是慢。优化索引后需要大概15分钟,具体看数据量。

很明显方案1还是解决不了问题,因为还是太慢了。

方案2,改成单表查询,然后聚合订单表的外键字段,再去批量查15张表的数据信息后,再聚合数据

方案2处理结果还是不行,还是慢,跟方案1的耗时差不多。

因为一开始去批量查15张表是串行的,也就是查完第一张表耗时10秒后,才能继续查第二张表,以此类推,所以最后的

耗时其实即使查16次表的时间总和加上数据聚合的时间。

相当于订到导出的耗时=1次订单表查询的时间+15张关联表每个的查询耗时总和+聚合数据的时间

方案3,改成单标查询,然后聚合订单表的外建字段,再用多线程异步批量查15张表的数据信息后,再聚合数据

方案3,暂时提高了效率,导出时间优化到了10分之1

相当于订到导出的耗时=1次订单表查询的时间+15张关联表中耗时最长的那次sql查询时间+聚合数据的时间

基于公司的保密,这里就简单演示下多线程的处理方式。

采用的是CompletableFuture,示例

模拟耗时的数据库查询方法,然后下文分别模拟了7个耗时,等同于去查询15张表外键关联表的操作,分别命名1,2,3,4,5,6,7

 private static String doThing1() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("dothing1");
        return "dothing1";
    }

模拟串行需要的时间

 public static void main(String[] args) throws Exception{
        long beign = System.currentTimeMillis();
        doThing1();
        doThing2();
        doThing3();
        doThing4();
        doThing5();
        doThing6();
        doThing7();
        long end = System.currentTimeMillis();
        System.out.println("总耗时="+(end-beign));
    }

耗时20004毫秒

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA3NzIyMzA=,size_16,color_FFFFFF,t_70

 

模拟并行的耗时

public static void main(String[] args) throws Exception{
        long beign = System.currentTimeMillis();
        //1
        CompletableFuture<String> thing1Future = CompletableFuture.supplyAsync(() -> {
            return doThing1();
        });

        //2
        CompletableFuture<String> thing2Future = CompletableFuture.supplyAsync(() -> {
            return doThing2();
        });

        //3
        CompletableFuture<String> thing3Future = CompletableFuture.supplyAsync(() -> {
            return doThing3();
        });

        //4
        CompletableFuture<String> thing4Future = CompletableFuture.supplyAsync(() -> {
            return doThing4();
        });

        //5
        CompletableFuture<String> thing5Future = CompletableFuture.supplyAsync(() -> {
            return doThing5();
        });

        //6
        CompletableFuture<String> thing6Future = CompletableFuture.supplyAsync(() -> {
            return doThing6();
        });

        //7
        CompletableFuture<String> thing7Future = CompletableFuture.supplyAsync(() -> {
            return doThing7();
        });

        //等所有任务完成再执行结果
        CompletableFuture.allOf(thing1Future, thing2Future,
                thing3Future,thing4Future,
                thing5Future,thing6Future,
                thing7Future).join();

        System.out.println("thing1Future -> " + thing1Future.get());
        System.out.println("thing2Future -> " + thing2Future.get());
        System.out.println("thing3Future -> " + thing3Future.get());
        System.out.println("thing4Future -> " + thing4Future.get());
        System.out.println("thing5Future -> " + thing5Future.get());
        System.out.println("thing6Future -> " + thing6Future.get());
        System.out.println("thing7Future -> " + thing7Future.get());
        long end = System.currentTimeMillis();
        System.out.println("总耗时="+(end-beign));
    }

耗时5043毫秒

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA3NzIyMzA=,size_16,color_FFFFFF,t_70

 

现在订单导出的处理方案,暂时就是按这种方式处理,后续如果有问题,应该还需要继续优化方案。

技能有限,如有更好的方案,欢迎文章下方留言讨论

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值