Skip to content

Commit f0ddeef

Browse files
Davidhua1996claude
andcommitted
#AI commit# CC: 优化作业执行列表查询性能:修复PageHelper分页失效与N+1,新增自定义count与索引DDL
1. 修复 getExecutedJobList 分页失效:PageHelper.startPage 在 current/size 校正之前调用, 且调用方无 defaultValue 的基本类型 int 在前端不传时绑定为0,startPage(0,0) 不追加 LIMIT 导致 getAllLaunchedJob 全表加载;将校正前置恢复 DB 层分页。 2. 消除 N+1:循环内逐个 selectTaskListByJobExecutionId 改为一次性批量 IN 查询 selectTaskMetricsByJobExecutionIds(仅取 job_execution_id/engine_type/metrics 三列), 内存按 jobExecutionId 分组计算 flow,逻辑等价。 3. 优化 count 查询:新增 getAllLaunchedJob_COUNT,PageHelper 按 _COUNT 后缀匹配, 只 count 单表 exchangis_launched_job_entity,去掉原 LEFT/INNER JOIN 的全表 JOIN count。 4. 新增阶段耗时日志:queryJob[count+paged]/queryTask/map/flow/jobCount/taskCount/pageTotal。 5. DDL:为 exchangis_launched_task_entity.job_execution_id 与 exchangis_launched_job_entity.create_time 添加索引,消除全表扫描与 filesort。 Optimize getExecutedJobList performance: fix PageHelper pagination failure and N+1, add custom count and index DDL 1. Fix pagination failure: PageHelper.startPage was called before current/size validation, and the caller's primitive int params (no defaultValue) bound to 0 when absent from the frontend; startPage(0,0) skips LIMIT and loads all jobs. Move validation before startPage to restore DB-level pagination. 2. Eliminate N+1: per-job selectTaskListByJobExecutionId in the loop is replaced by a single batch IN query selectTaskMetricsByJobExecutionIds (only job_execution_id/ engine_type/metrics columns), grouped in memory by jobExecutionId to compute flow; logic is equivalent. 3. Optimize count query: add getAllLaunchedJob_COUNT (matched by PageHelper via the _COUNT suffix) that counts only exchangis_launched_job_entity, dropping the full LEFT/INNER JOIN count of the original SQL. 4. Add per-stage timing logs: queryJob[count+paged]/queryTask/map/flow/jobCount/ taskCount/pageTotal. 5. DDL: add indexes on exchangis_launched_task_entity.job_execution_id and exchangis_launched_job_entity.create_time to remove full table scans and filesort. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 85b10cd commit f0ddeef

5 files changed

Lines changed: 112 additions & 8 deletions

File tree

db/1.1.17/exchangis_ddl.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Add index for job_execution_id field in exchangis_launched_task_entity table
2+
-- 为exchangis_launched_task_entity表的job_execution_id字段添加索引(消除作业列表查询的全表扫描)
3+
ALTER TABLE exchangis_launched_task_entity ADD INDEX `job_execution_id_idx`(`job_execution_id`);
4+
5+
-- Add index for create_time field in exchangis_launched_job_entity table
6+
-- 为exchangis_launched_job_entity表的create_time字段添加索引(消除作业列表 ORDER BY create_time 的 filesort 及范围扫描)
7+
ALTER TABLE exchangis_launched_job_entity ADD INDEX `idx_create_time`(`create_time`);

exchangis-job/exchangis-job-server/src/main/java/com/webank/wedatasphere/exchangis/job/server/mapper/LaunchedTaskDao.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ public interface LaunchedTaskDao {
102102

103103
List<LaunchedExchangisTaskEntity> selectTaskListByJobExecutionId(@Param("jobExecutionId") String jobExecutionId);
104104

105+
/**
106+
* Batch query task entities (metrics-related columns only) by job execution ids,
107+
* used to calculate job flow without loading heavy columns (content/linkis_job_info etc.)
108+
* @param jobExecutionIds job execution id list
109+
* @return task entity list (only jobExecutionId/engineType/metrics populated)
110+
*/
111+
List<LaunchedExchangisTaskEntity> selectTaskMetricsByJobExecutionIds(@Param("jobExecutionIds") List<String> jobExecutionIds);
112+
105113
/**
106114
* Select status list
107115
* @param jobExecutionId job execution id

exchangis-job/exchangis-job-server/src/main/java/com/webank/wedatasphere/exchangis/job/server/mapper/impl/LaunchedJobMapper.xml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,39 @@
232232
order by create_time desc
233233
</select>
234234

235+
<!--
236+
Custom count for PageHelper (matched by id suffix "_COUNT"): count only the
237+
exchangis_launched_job_entity table instead of the full LEFT/INNER JOIN in
238+
getAllLaunchedJob, because all filter columns live on table l. Assumes
239+
launched_job.job_id always has a matching exchangis_job_entity + project_info
240+
(true in normal exchangis usage); otherwise pageTotal may be slightly larger.
241+
-->
242+
<select id="getAllLaunchedJob_COUNT" resultType="java.lang.Long">
243+
SELECT count(*)
244+
FROM
245+
`exchangis_launched_job_entity` l
246+
<where>
247+
<if test="jobExecutionId.trim() != '' and jobExecutionId != null">
248+
and l.job_execution_id = #{jobExecutionId}
249+
</if>
250+
<if test="launchStartTime != null">
251+
and l.create_time >= #{launchStartTime}
252+
</if>
253+
<if test="launchEndTime != null">
254+
and l.create_time &lt;= #{launchEndTime}
255+
</if>
256+
<if test="isAdminUser != null and isAdminUser == false">
257+
and l.create_user = #{createUser}
258+
</if>
259+
<if test="status.trim() != '' and status != null">
260+
and l.status = #{status}
261+
</if>
262+
<if test="jobName.trim() != '' and jobName != null">
263+
and l.name like concat('%', #{jobName}, '%')
264+
</if>
265+
</where>
266+
</select>
267+
235268
<select id="count" resultType="java.lang.Integer">
236269
SELECT count(*)
237270
FROM

exchangis-job/exchangis-job-server/src/main/java/com/webank/wedatasphere/exchangis/job/server/mapper/impl/LaunchedTaskMapper.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,23 @@
204204
where job_execution_id = #{jobExecutionId}
205205
</select>
206206

207+
<!-- Lightweight result map for metrics-related columns only (flow calculation) -->
208+
<resultMap id="TaskMetricsMap" type="com.webank.wedatasphere.exchangis.job.launcher.entity.LaunchedExchangisTaskEntity">
209+
<result column="job_execution_id" property="jobExecutionId"/>
210+
<result column="engine_type" property="engineType"/>
211+
<result column="metrics" property="metrics"/>
212+
</resultMap>
213+
214+
<select id="selectTaskMetricsByJobExecutionIds" resultMap="TaskMetricsMap">
215+
select job_execution_id, engine_type, metrics
216+
from
217+
<include refid="TableName" />
218+
where job_execution_id in
219+
<foreach collection="jobExecutionIds" item="item" open="(" separator="," close=")">
220+
#{item}
221+
</foreach>
222+
</select>
223+
207224
<select id="selectTaskStatusByJobExecutionId" resultType="String">
208225
<![CDATA[SELECT status FROM ]]>
209226
<include refid="TableName" />

exchangis-job/exchangis-job-server/src/main/java/com/webank/wedatasphere/exchangis/job/server/service/impl/DefaultJobExecuteService.java

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -271,24 +271,61 @@ public ExchangisCategoryLogVo getTaskLogInfo(String taskId, String jobExecutionI
271271
@Override
272272
public PageResult<ExchangisLaunchedJobListVo> getExecutedJobList(String jobExecutionId, String jobName, String status,
273273
Long launchStartTime, Long launchEndTime, int current, int size, HttpServletRequest request) throws ExchangisJobServerException {
274-
PageHelper.startPage(current, size);
274+
long totalStart = System.currentTimeMillis();
275275
if (current <= 0) {
276276
current = 1;
277277
}
278278
if (size <= 0) {
279279
size = 10;
280280
}
281+
// NOTE: startPage must use the validated current/size, otherwise a missing/zero paging
282+
// param from the caller (bound to 0 as primitive int) makes PageHelper skip LIMIT and
283+
// getAllLaunchedJob would load all jobs.
284+
PageHelper.startPage(current, size);
281285
List<ExchangisLaunchedJobListVo> jobList = new ArrayList<>();
282286
Date startTime = launchStartTime == null ? null : new Date(launchStartTime);
283287
Date endTime = launchEndTime == null ? null : new Date(launchEndTime);
284288
String loginUser = UserUtils.getLoginUser(request);
289+
// queryJobCost covers both PageHelper count(*) and the paged select (two DB round-trips)
290+
long queryJobStart = System.currentTimeMillis();
285291
List<LaunchedExchangisJobEntity> jobEntitylist =
286292
launchedJobDao.getAllLaunchedJob(jobExecutionId, jobName, status, startTime, endTime,
287293
loginUser, GlobalConfiguration.isAdminUser(loginUser));
294+
long queryJobCost = System.currentTimeMillis() - queryJobStart;
288295
PageInfo<LaunchedExchangisJobEntity> pageInfo = new PageInfo<>(jobEntitylist);
296+
// Batch load task metrics for all jobs in the current page to avoid N+1 queries,
297+
// then group by jobExecutionId so that each job's flow can be computed in memory.
298+
Map<String, List<LaunchedExchangisTaskEntity>> taskMapByJobExecutionId = new HashMap<>();
299+
long queryTaskCost = 0L;
300+
int taskCount = 0;
301+
if (jobEntitylist != null && !jobEntitylist.isEmpty()) {
302+
List<String> jobExecutionIdList = new ArrayList<>(jobEntitylist.size());
303+
for (LaunchedExchangisJobEntity launchedExchangisJobEntity : jobEntitylist) {
304+
if (StringUtils.isNotBlank(launchedExchangisJobEntity.getJobExecutionId())) {
305+
jobExecutionIdList.add(launchedExchangisJobEntity.getJobExecutionId());
306+
}
307+
}
308+
if (!jobExecutionIdList.isEmpty()) {
309+
long queryTaskStart = System.currentTimeMillis();
310+
List<LaunchedExchangisTaskEntity> allTaskEntities =
311+
launchedTaskDao.selectTaskMetricsByJobExecutionIds(jobExecutionIdList);
312+
queryTaskCost = System.currentTimeMillis() - queryTaskStart;
313+
if (allTaskEntities != null) {
314+
taskCount = allTaskEntities.size();
315+
for (LaunchedExchangisTaskEntity launchedExchangisTaskEntity : allTaskEntities) {
316+
taskMapByJobExecutionId
317+
.computeIfAbsent(launchedExchangisTaskEntity.getJobExecutionId(), k -> new ArrayList<>())
318+
.add(launchedExchangisTaskEntity);
319+
}
320+
}
321+
}
322+
}
323+
long mapCost = 0L;
324+
long flowCost = 0L;
289325
if (jobEntitylist != null) {
290326
try {
291327
for (LaunchedExchangisJobEntity launchedExchangisJobEntity : jobEntitylist) {
328+
long mapStart = System.currentTimeMillis();
292329
ExchangisLaunchedJobListVo exchangisJobVo = modelMapper.map(launchedExchangisJobEntity, ExchangisLaunchedJobListVo.class);
293330
if (launchedExchangisJobEntity.getExchangisJobEntity() == null || launchedExchangisJobEntity.getExchangisJobEntity().getSource() == null) {
294331
exchangisJobVo.setExecuteNode("-");
@@ -299,25 +336,24 @@ public PageResult<ExchangisLaunchedJobListVo> getExecutedJobList(String jobExecu
299336
.getOrDefault("executeNode", "-")));
300337
}
301338
}
302-
List<LaunchedExchangisTaskEntity> launchedExchangisTaskEntities = launchedTaskDao.selectTaskListByJobExecutionId(launchedExchangisJobEntity.getJobExecutionId());
339+
mapCost += System.currentTimeMillis() - mapStart;
340+
List<LaunchedExchangisTaskEntity> launchedExchangisTaskEntities = taskMapByJobExecutionId.get(launchedExchangisJobEntity.getJobExecutionId());
303341
if (launchedExchangisTaskEntities == null) {
304342
exchangisJobVo.setFlow((long) 0);
305343
} else {
306344
double flows = 0;
307345
int taskNum = launchedExchangisTaskEntities.size();
346+
long flowStart = System.currentTimeMillis();
308347
for (LaunchedExchangisTaskEntity launchedExchangisTaskEntity : launchedExchangisTaskEntities) {
309-
MetricsConverter<ExchangisMetricsVo> metricsConverter = metricConverterFactory.getOrCreateMetricsConverter(launchedExchangisTaskEntity.getEngineType());
310-
ExchangisLaunchedTaskMetricsVo exchangisLaunchedTaskVo = new ExchangisLaunchedTaskMetricsVo();
311348
if (launchedExchangisTaskEntity.getMetricsMap() == null) {
312-
flows += 0;
313349
continue;
314350
}
351+
MetricsConverter<ExchangisMetricsVo> metricsConverter = metricConverterFactory.getOrCreateMetricsConverter(launchedExchangisTaskEntity.getEngineType());
352+
ExchangisLaunchedTaskMetricsVo exchangisLaunchedTaskVo = new ExchangisLaunchedTaskMetricsVo();
315353
exchangisLaunchedTaskVo.setMetrics(metricsConverter.convert(launchedExchangisTaskEntity.getMetricsMap()));
316-
Map<String, Object> flowMap = (Map<String, Object>) launchedExchangisTaskEntity.getMetricsMap().get("traffic");
317-
//Map<String, Object> flowMap = (Map<String, Object>) launchedExchangisTaskEntity.getMetricsMap().get("traffic");
318-
//flows += flowMap == null ? 0 : Integer.parseInt(flowMap.get("flow").toString());
319354
flows += exchangisLaunchedTaskVo.getMetrics().getTraffic().getFlow();
320355
}
356+
flowCost += System.currentTimeMillis() - flowStart;
321357
exchangisJobVo.setFlow(taskNum == 0 ? 0 : (long) (flows / taskNum));
322358
}
323359
jobList.add(exchangisJobVo);
@@ -326,6 +362,9 @@ public PageResult<ExchangisLaunchedJobListVo> getExecutedJobList(String jobExecu
326362
LOG.error("Exception happened while get JobLists mapping to Vo(获取job列表映射至页面是出错,请校验任务信息), " + "message: " + e.getMessage(), e);
327363
}
328364
}
365+
int jobCount = jobEntitylist == null ? 0 : jobEntitylist.size();
366+
LOG.info("getExecutedJobList stage cost(获取已执行作业列表各阶段耗时), total={}ms, queryJob={}ms[count+paged], queryTask={}ms, map={}ms, flow={}ms, jobCount={}, taskCount={}, pageTotal={}",
367+
System.currentTimeMillis() - totalStart, queryJobCost, queryTaskCost, mapCost, flowCost, jobCount, taskCount, pageInfo.getTotal());
329368
PageResult<ExchangisLaunchedJobListVo> pageResult = new PageResult<>();
330369
pageResult.setList(jobList);
331370
pageResult.setTotal(pageInfo.getTotal());

0 commit comments

Comments
 (0)