【实战】大批量数据导出的计划

布景

业务需求导出将近6w多的全单位的数据,有些数据在其时表中不存在,需求现计算。这个功用是汇总的功用,并且涉及的表很多(将近40张),表是真TM的多,需求显现的字段也是超多,我是真服了,其时是怎么规划的。

计划

优化架构和表结构是不可的,只能在这40张表的基础上持续搞。想的办法是分隔批量查询。主体思维便是先把首要的数据查询出来,再写多个子查询(涉及到计算的),子查询都用 in 来写,一次查询上千条,然后这样再分批次,最终再汇总。

详细实现操作

这是主表,首要的数据,里面会查询出project_id,再去根据project_id 去作为其他子查询的条件。这儿 * 省掉详细的字段。

select * from
serp_em_project_info a
left join serp_em_construction_plan b
on a.project_id = b.project_id
left join serp_em_project_account_info c
on a.project_id = c.project_id
left join js_sys_office o
on a.office_code = o.office_code
left join serp_base_project_developer d
on a.project_developer =d.project_developer_id
left join  js_sys_area e
on a.construction_area = e.area_code
left join js_sys_office uo
on uo.office_code = a.undertaking_office
left join js_sys_user creator
on creator.user_code =a.project_manager

然后再分批次,sumAmountHandlerList 办法中传的参数便是 咱们查询出的首要数据

public List<Map<String, Object>> sumAmountHandlerList(List<Map<String, Object>> list) {
    
    // 一批次的数量,将2500 个 project_id 放在一个调集里
    int batchNumber = 2500;
​
    // 循环
    int iteratorCount = (int) Math.ceil((double) list.size() / batchNumber);
    for (int i = 0; i < iteratorCount; i++) {
      int startIndex = i * batchNumber;
      int endIndex = (i < iteratorCount - 2) ? (startIndex + batchNumber - 1) : (list.size() - 1);
​
      // 取一切的 'projectID'
      List<String> projectIds = new ArrayList<>();
      for (int j = startIndex; j <= endIndex; j++) {
        projectIds.add((String) list.get(j).get("project_id"));
       }
​
     //核定告贷合计,核定告贷金额,子查询,需求现计算
      List<Map<String, Object>> individualBorrowList = projectReportDao.individualBorrowCollection(projectIds) ;
​
​
      // 数据处理
      for (int j = startIndex; j <= endIndex; j++) {
        Map<String, Object> item = list.get(j);
​
        // 核定告贷金额(authorized)
        item.put("authorized", 0D);
        for (Map<String, Object> authorizedItem : individualBorrowList) {
          if (((String) authorizedItem.get("project_id")).equals((String) item.get("project_id"))) {
            item.put("authorized", Double.parseDouble(authorizedItem.get("authorized").toString()));
            break;
           }
         }
       }

这块,首要讲一下,怎么分批次。先获取到主体数据的总数,再根据一个批次里的数量,获取到需求几个批次,就能够悉数加载完数据。也便是外循环几回。

  // 循环
    int iteratorCount = (int) Math.ceil((double) list.size() / batchNumber);
    for (int i = 0; i < iteratorCount; i++) {
       int startIndex = i * batchNumber;
      int endIndex = (i < iteratorCount - 2) ? (startIndex + batchNumber - 1) : (list.size() - 1);

第一次内循环是从0开端,第2次内循环便是 1 * 批次数量,依次类推。 int startIndex = i * batchNumber;

第一次内循环是从(批次数量-1) 完毕,因为是从0开端的,第2次内循环便是 2500开端,到2500+batchNumber – 1 完毕,

最终一次内循环便是 总数-1;

这儿比较绕,梳理通了,整体就简略了,最好是带上详细的数字就简略多了。

然后便是在内循环中,根据project_id ,进行比对,相同的,将数据组合在一起。

其他计划

其时,也有考虑采取守时使命,在凌晨将数据悉数算好,然后放到一张表里,这样直接查询一张表,必定功能会更好一些。但数据会存在推迟性,当天审批过的数据,业务人员无法查看到,只要第二天守时使命完了,才能够查询。采取分批次子查询的计划查询在1s内就能够查询出来,导出时,由于数据较多,需求五六分钟(将近20M),业务人员也能够承受。

看看,大家还有什么比较好的计划?欢迎讨论。