背景
特定查询条件下测试数据量 70w (查询条件优化并命中了组合索引),group by 聚合后 3w 条数据,并进行导出为Excel
1. 查询数据库
select * from xxx group by user where create_date BETWEEN ‘’ AND ‘’
1.1 分页查询
假如分页大小为 1000, 需要执行 30 次SQL才能得到所有数据。
此时MySQL扫描的行数是 70w * 30 = 2100w。
由于 group by 使用了中间表,当分页执行到尾声,性能下降特别明显
例如 select * from xxx group by user limit 28000, 1000;
1.2 Stream 查询
- 声明
@Select("SELECT * FROM xxx where create_date BETWEEN #{start} AND #{end} GROUP BY user") @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE) @ResultType(Report.class) void selectAutoList(@Param("start") Date start, @Param("end") Date end, ResultHandler<Report> handler);
- 使用
Date start = Date.from(LocalDateTime.now().plusDays(-500).atZone(ZoneId.systemDefault()).toInstant()); List<xxx> result = new ArrayList<>(); xxxDao.selectAutoList(start, new Date(), ctx -> { Report val = ctx.getResultObject(); result.add(val); });
下图MySQL的CPU监控图中,第一个波峰是Stream模式。 第二个高平峰是分页查询模式
2. 导出Excel
同样使用Stream模式,使用 buffer flush缓存到文件, 避免OOM 风险