Java 从查询超时到性能提升 (实战讲解)
目录
- 1. 问题所示
- 2. 原理分析
- 3. 解决方法
- 3.1 代码优化
- 3.2 索引优化
- 3.3 删数据
1. 问题所示
查询返回速度慢,导致前端页面无数据显示
前端和后端均未报错,但后端未能在合理时间内返回结果到前端
后端没有报错日志
2. 原理分析
单独分析代码中的对算法有所阻塞的位置!
后续在分析对DB中的阻塞位置!
最后研究数据是否过载,服务
查询超时问题通常发生在以下场景:
- 数据量巨大: 数据表中记录过多,导致全表扫描耗时过长
- SQL语句问题: 例如缺少必要的过滤条件或排序操作未使用索引
- 索引缺失或无效: 查询字段未建立索引,导致数据库无法高效检索数据
3. 解决方法
3.1 代码优化
将 for 循环替换为 Java Stream API 的方式,这样代码更加简洁且可读性更高
@GetMapping("/getUserCheckList")
public R<List<ChangeShiftsRuleDetailVO>> getUserCheckList(String type){Long ruleId = changeShiftsRuleService.getIdByType(type);List<ChangeShiftsRuleDetailEntity> entityList = changeShiftsRuleDetailService.getListByRuleId(ruleId);List<ChangeShiftsRuleDetailVO> voList = new ArrayList<>();//ChangeShiftsRuleDetailWrapper.build().listVO(entityList);for (ChangeShiftsRuleDetailEntity entity:entityList) {ChangeShiftsRuleDetailVO vo = new ChangeShiftsRuleDetailVO();vo = entityVO(entity);voList.add(vo);}return R.data(voList);
}public ChangeShiftsRuleDetailVO entityVO(ChangeShiftsRuleDetailEntity entity) {ChangeShiftsRuleDetailVO vo = BeanUtil.copy(entity,ChangeShiftsRuleDetailVO.class);Long ruleDetailId = vo.getId();if (ruleDetailId != null){ChangeShiftsRecordDetailEntity changeShiftsRecordDetailEntity = changeShiftsRecordDetailService.selectLastByRuleDetailId(ruleDetailId);vo.setEquipmentNo(changeShiftsRecordDetailEntity == null ? null :changeShiftsRecordDetailEntity.getEquipmentNo());vo.setNormal(changeShiftsRecordDetailEntity == null ? true :changeShiftsRecordDetailEntity.getIsNormal());}return vo;
}
优化如下:
@GetMapping("/getUserCheckList")
public R<List<ChangeShiftsRuleDetailVO>> getUserCheckList(String type){Long ruleId = changeShiftsRuleService.getIdByType(type);List<ChangeShiftsRuleDetailEntity> entityList = changeShiftsRuleDetailService.getListByRuleId(ruleId);// 使用Stream API转换为VO列表List<ChangeShiftsRuleDetailVO> voList = entityList.stream().map(this::entityVO) // 调用entityVO方法进行转换.collect(Collectors.toList());return R.data(voList);
}
使用stream或者for,需要结合实际场景测试ms多少:详细分析Java中Stream流和for循环的差异之处
3.2 索引优化
查询各语句输出的秒数,并结合索引优化语句:Mysql优化高级篇(全)
对应增加多一个索引,可以是普通索引
也可以是联合索引
结果如下:
此处补充下索引的基本知识:
查看索引信息
SHOW INDEX FROM table_name;
或者使用如下:
SELECTTABLE_NAME,NON_UNIQUE,INDEX_NAME,SEQ_IN_INDEX,COLUMN_NAME,COLLATION,CARDINALITY,SUB_PART,PACKED,NULLABLE,INDEX_TYPE,COMMENT,INDEX_COMMENT
FROMINFORMATION_SCHEMA.STATISTICS
WHERETABLE_SCHEMA = 'your_database_name'AND TABLE_NAME = 'table_name';
截图如下:
以下是实战内容:
创建普通索引:
ALTER TABLE equipment_change_shifts_record_detail ADD INDEX index_rule_detail_id (rule_detail_id);
或者
CREATE INDEX index_rule_detail_id ON equipment_change_shifts_record_detail(rule_detail_id);
创建联合索引:
ALTER TABLE equipment_change_shifts_record_detail ADD INDEX index_rule_detail_id_is_deleted (rule_detail_id, is_deleted);
或者
CREATE INDEX index_rule_detail_id_is_deleted ON equipment_change_shifts_record_detail(rule_detail_id, is_deleted);
后续如果要删除索引,可以使用如下方式:DROP INDEX index_name ON table_name;
3.3 删数据
原本是有213w的数据,但是对于此场景四表联合查询来说不是很合适,对此进行优化:
删除一些历史数据:
DELETE FROM equipment_change_shifts_record_detail
WHERE create_time <= '2024-08-01 00:00:00';