优化化成报表列表与详情接口性能
消除列表逐报表查询最新版本的 N+1 访问,并避免新快照重复保存逐工步采样。保留共享循环曲线、历史快照和普通报表摘要接口边界。
| | |
| | | /** 列表来源名称取自已保存版本,测试删除后仍保留筛选与识别信息。 */ |
| | | public List<Summary> list() |
| | | { |
| | | return reports.list().stream().map(summary -> { |
| | | var version = reports.get(summary.id()); |
| | | var sources = items(JSON.parseObject(version.snapshotJson())); |
| | | return reports.listWithSnapshots().stream().map(summary -> { |
| | | // 最新快照由一次列表 SQL 带出,避免每份报表再执行一次版本查询。 |
| | | var sources = items(JSON.parseObject(summary.snapshotJson())); |
| | | return new Summary(summary.id(), summary.name(), summary.creator(), summary.createdAt(), |
| | | String.join("、", sources.stream().map(item -> item.source().name()).distinct().toList()), |
| | | String.join("、", sources.stream().map(item -> item.source().batteryGroup()).distinct().toList()), version.versionNo()); |
| | | String.join("、", sources.stream().map(item -> item.source().batteryGroup()).distinct().toList()), summary.versionNo()); |
| | | }).toList(); |
| | | } |
| | | |
| | |
| | | var actual = Stream.of(rows, realtime, |
| | | batteryRows(steps.computeIfAbsent(selection.testId(), data::steps), battery)).flatMap(List::stream) |
| | | .map(this::cycleNo).filter(no -> no > 0).distinct().sorted().toList(); |
| | | items.add(new Item(candidate(test, battery), actual, rows, metrics(rows, actual), battery.getFields(), chargeSteps(steps.get(selection.testId()), realtime, battery, actual), curves(realtime, actual), stepCurves(realtime, actual))); |
| | | // 图表只需按循环共享的曲线;逐工步曲线会重复保存同一批采样,造成详情响应膨胀。 |
| | | items.add(new Item(candidate(test, battery), actual, rows, metrics(rows, actual), battery.getFields(), chargeSteps(steps.get(selection.testId()), realtime, battery, actual), curves(realtime, actual), null)); |
| | | } |
| | | return new Matrix(items, items.stream().flatMap(item -> item.cycleNos().stream()).distinct().sorted().toList()); |
| | | } |
| | |
| | | private String sql(String statement) { return statement.replace("t_compare_report", "t_" + type + "_report"); } |
| | | |
| | | public record Summary(long id, String name, String creator, long createdAt) { } |
| | | /** 仅供需要从快照提取列表展示字段的化成服务使用;普通报表列表不返回快照。 */ |
| | | public record SummarySnapshot(long id, String name, String creator, long createdAt, int versionNo, String snapshotJson) { } |
| | | public record Version(Summary report, int versionNo, String snapshotJson, String operatorName, long versionCreatedAt, String changeSummary) { } |
| | | public record History(int versionNo, String operatorName, long createdAt, String changeSummary) { } |
| | | |
| | |
| | | (rs, index) -> new Summary(rs.getLong(1), rs.getString(2), rs.getString(3), rs.getTimestamp(4).getTime())); |
| | | } |
| | | |
| | | public List<SummarySnapshot> listWithSnapshots() |
| | | { |
| | | return jdbc.query(sql("select r.report_id, r.report_name, r.creator_name, r.created_at_utc, v.version_no, v.snapshot_json " |
| | | + "from t_compare_report r join t_compare_report_version v on v.report_id=r.report_id " |
| | | + "and v.version_no=(select max(v2.version_no) from t_compare_report_version v2 where v2.report_id=r.report_id) " |
| | | + "order by r.created_at_utc desc, r.report_id desc"), |
| | | (rs, index) -> new SummarySnapshot(rs.getLong(1), rs.getString(2), rs.getString(3), rs.getTimestamp(4).getTime(), rs.getInt(5), rs.getString(6))); |
| | | } |
| | | |
| | | /** 重读最新完整版本;来源不存在不影响结果。 */ |
| | | public Version get(long id) |
| | | { return get(id, null); } |
| | |
| | | assertEquals(250, values.getBigDecimal("1|11|1|capacity1v").intValueExact()); |
| | | assertEquals(50, values.getBigDecimal("1|11|1|capacity1vf").intValueExact()); |
| | | assertEquals(5, saved.getJSONArray("items").getJSONObject(0).getJSONArray("businessFields").size()); |
| | | assertNull(saved.getJSONArray("items").getJSONObject(0).get("stepCurves"), "新快照不应重复保存逐工步采样"); |
| | | assertEquals(1, service.list().get(0).versionNo()); |
| | | clearInvocations(tests, data); |
| | | assertEquals(values, JSON.parseObject(JSON.toJSONString(service.get(saved.getLongValue("id"), null))).getJSONObject("calculatedValues")); |