シーンの説明:
MySQLのINの問題:inのコンテンツが大きすぎるため(5000以上)、クエリの効率が低くなります(4秒以上)。
SELECT * FROM xxx WHERE `id` IN(xxx)
計画されたソリューション:
1.测试得到IN里面的最佳数量
2.循环分多次查询
3.多线程共同执行
実際のテスト記録:
1.最良の数量を問い合わせる
1次 4265ms、4177ms、4112ms 平均4.18秒 5643条
2次 1128ms、1105ms、1117ms 平均2.23秒 2822条
3次 326ms、298ms、326ms 平均1.27秒 1411条
8次 117ms、91ms、88ms、100ms、86ms 平均0.77秒 705条
20次 43 32 24 25 34 23 24 27 28 22 平均0.56秒 282条
40次 25 16 11 10 13 10 10 10 13 10 平均0.51秒 141条
30次 29 18 17 13 14 15 15 17 15 17 平均0.51秒 188条
結論:
20次和40次差距不大,又测试了30次的数据结果,结果和40次一样。
mysql查询次数对性能也有影响,所以我们以200条定为最佳数量值进行测试.
2.ループクエリ(29回)
Integer total = orderIds.size();
Integer size = 200;
Integer pages = total % size == 0 ? total / size : total / size + 1;
List<Order> finalRes = new ArrayList<Order>(total);
for (int i = 0; i < pages; i++) {
Integer toIndex = (i + 1) * size > total ? total : (i + 1) * size;
//分批查询
List<Order> orderList = orderMapper.selectList(new EntityWrapper<Order>().in("id", orderIds.subList(i * size, toIndex)));
//组装结果
finalRes.addAll(orderList);
}
演算結果:
455ms、451ms、450ms 平均时间:0.45秒
3.マルチスレッド(12コア)
Integer size = 200;
Integer total = orders.size();
Integer pages = total % size == 0 ? total / size : total / size + 1;
//线程池
ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List<InOrderIds> callables = new ArrayList<>();
for (int i = 0; i < pages; i++) {
Integer toIndex = (i + 1) * size > total ? total : (i + 1) * size;
callables.add(new InOrderIds(orderIds.subList(i * size, toIndex), i));
}
List<Future<List<Order>>> futures = service.invokeAll(callables);
List<Order> finalRes = new ArrayList<Order>(total);
futures.forEach((f) -> {
try {
System.out.println(finalRes.addAll(f.get()));
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
});
service.shutDown();//释放资源
演算結果:
单核CPU 256ms、225ms、252ms 平均时间:0.244秒
多核(12)CPU 76ms、42ms、72ms 平均时间:0.063秒
最終的な結論:
IN里面最多200条达到性能瓶颈;
循环查询能提升近8-9倍的效率;
多线程是性能最好的,建议使用。