我数据库现在有5w条数据 每次从Excel导入200条 ,我数据库表有一个 detail 字段 每次导入都需要判断 detail 字段与全部数据的detail 字段的相似度,超过百分之八十 就给这条数据的 state字段赋值为1 否则就赋值0 我用stream流还是太慢, 怎么优化
下面是我写的
@Service
@Transactional
public class fileServiceImpl implements fileService {
//相似度阈值
private static final double SIMILARITY = 0.8;
@Autowired
private WorkDtlDao workDtlDao;
@Autowired
private WorkTeamDao workTeamDao;
/**
* @param dailyImports excel导入的数据
* @param beginDate 前端传的开始时间
* @param endDate 结束时间
* @param week 第几周
*/
@Override
public void importFrom2Time(List<WorkDtl> dailyImports, String beginDate, String endDate, String week) {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
//一次查询 减少数据库io 废内存
CopyOnWriteArrayList<String> strings = workDtlDao.selectByGsDetail();
//迭代器 伪多线程
dailyImports.forEach(e -> {
e.setWeek(week);
e.setBeginDate(format.format(new Date(Long.parseLong(beginDate))));
e.setEndDate(format.format(new Date(Long.parseLong(endDate))));
e.setUid(UUID.randomUUID().toString());
e.setState(0);
// AtomicReference<Double> num = new AtomicReference<>(0.0);
// strings.forEach(es -> {
//
// });
//设置标准可以提前跳出for循环
double num = 0.0;
for (String es : strings) {
num = TextSimilarity.sim(es, e.getGsDetail());
// num.set(sim > num.get() ? sim : num.get());
if (num > SIMILARITY) {
break;
}
}
e.setState(num >= SIMILARITY ? 1 : 0);
workDtlDao.insert(e);
//把信曾的数据加到list中,不需要再次查询数据库,减少io
// if (e.getState().equals(0))
strings.add(e.getGsDetail());
});
}
这个例子中,用批量写的方式会比用多线程有更好的优化效果。
如果非要用多线程的话,有两种解决方法:
1.(推荐)使用生产者消费者模型,将处理好的数据写到一个线程安全的队列中,用消费者读取这个队列并批量写入数据库
2.(不推荐)用stream的parallel方法,将流变为并发的 https://docs.oracle.com/javase/tutorial/collections/streams/parallelism.html
我看你46行代码是单条插入把,可以考虑将结果存到一个list中,然后批量插入。
导入是非常费数据库性能的,你每次一条一条导入,边导入边比较,是非常慢的,你现在还是40几条,等你几万条的时候,不得等个十几分钟?所以这种解决方案就是,先全部一次性导入,可以利用数据的批量插入,然后导入成功后,然后处理相似的,不管是删除条,还是改状态
您好,我是问答小助手,你的问题已经有小伙伴为您解答了问题,您看下是否解决了您的问题。
如果有您比较满意的答案 / 帮您提供解决思路的答案,可以点击【采纳】按钮,给回答的小伙伴一些鼓励哦~~