java解决mysql大数据联查问题
近期有一个需求是联查两张表比对三个字段
一般用mysql就可以解决
SELECT
*
FROM
tb_a a
LEFT JOIN b ON a.test = b.test
AND a.NAME = b.NAME
AND a.type = b.type
但是表a和表b的数据量都很不小,大概在10w左右,由于并不是以固定的id去关联,加了索引也没有效果,使用navicate根本就查不出来。
这时候想到了使用java去查,一开始采用的是双重for去比对,但是导致内存溢出根本差不出来。
后来想到了使用map利用这三个字段作为key去查,查询结果很快,大概几秒内就查出来了,由于这次是一个数据比对导出,不涉及到上线业务,所以就没有进行进一步的优化。
下面是核心代码
public List<NoWidCompareDTO> getNoWidCompare() {
List<NoWidCompareDTO> result = new ArrayList<>();
// 为了方便直接查的,可以优化查询
List<EEaResourceDataWidNo> noWidList = noWidMapper.selectList(null);
List<CollectionAllLevel> otherList = allLevelMapper.selectList(null);
log.info("开始比对:{}", DateUtil.now());
// 构建一个以三个条件为键,CollectionAllLevel对象为值的Map,方便后续查找
Map<String, CollectionAllLevel> otherMap = new HashMap<>();
for (CollectionAllLevel allLevelDTO : otherList) {
String key = getKey(allLevelDTO);
otherMap.put(key, allLevelDTO);
}
for (EEaResourceDataWidNo noWidDTO : noWidList) {
String key = getKey(noWidDTO);
CollectionAllLevel allLevelDTO = otherMap.get(key);
// 构建NoWidCompareDTO,并进行属性复制
NoWidCompareDTO dto = BeanUtil.toBean(noWidDTO, NoWidCompareDTO.class);
if (allLevelDTO != null) {
// 如果比对成功进行复制
BeanUtil.copyProperties(allLevelDTO, dto);
}
// 都要添加进去
result.add(dto);
}
log.info("比对结束:{}", DateUtil.now());
return result;
}
/**
* 等级,馆藏名称,资源名称统一设置为key,当然也可以在查询的时候直接设置
*/
private String getKey(EEaResourceDataWidNo noWidDTO) {
return noWidDTO.getLevel() + "_" + noWidDTO.getCollectionUnits() + "_" + noWidDTO.getResourceName();
}
/**
* 等级,馆藏名称,资源名称统一设置为key,当然也可以在查询的时候直接设置
*/
private String getKey(CollectionAllLevel allLevelDTO) {
return allLevelDTO.getOtherLevel() + "_" + allLevelDTO.getMuseumCollectionName() + "_" + allLevelDTO.getCollectionName();
}
这效果和以a表作为主表进行左连接查询一样。
总之上面的代码仅作为简单的操作,还有一些逻辑都没校验,也可以进行优化,重点就是使用map的key,value进行操作比对