将一次性查询改为通过分片、异步优化 in子查询
集合数据分片是将数据按指定大小进行分组,像java中使用guava或hutool工具的partition进行分组,然后分批处理或者获取数据,in子查询会通过创建临时表,不易将大量数据放入in子查询中
案例:分片+异步操作
@Test
void test32() {
ExecutorService orderExecutorService = Executors.newFixedThreadPool(10);
List<Integer> userIds = new CopyOnWriteArrayList<>();
userIds.add(1);
userIds.add(2);
userIds.add(3);
userIds.add(4);
userIds.add(5);
List<List<Integer>> partitionUserIds = ListUtil.partition(userIds, 2);
final List<Object> allOrders = new ArrayList<>(partitionUserIds.size());
// 分片+异步
partitionUserIds.stream().map(item -> {
return CompletableFuture.runAsync(() -> {
// 查询数据库并添加到集合中
ArrayList<Object> data = new ArrayList<>();
allOrders.addAll(data);
}, orderExecutorService);
}).forEach(CompletableFuture::join);
// 执行业务操作
allOrders.forEach(System.out::println);
}
分片实现原理
/**
* 集合分片处理
*
* @param datas 需要分片的集合
* @param limit 一个分片大小
* @param <T>
* @return
*/
public static <T> List<List<T>> toPart(List<T> datas, int limit) {
if (datas == null || datas.size() == 0) {
throw new RuntimeException("数据不能为空");
}
int size = datas.size();
if (size <= limit) {
return Collections.singletonList(datas);
}
List<List<T>> partsList = new ArrayList<>();
// 已经查询的条数
int passIndex = 0;
do {
int endIndex = Math.min(passIndex + limit, size);
// 注意subList是前闭后开,开始索引与结束索引不能一样
List<T> currPartList = datas.subList(passIndex, endIndex);
partsList.add(currPartList);
passIndex = endIndex;
} while (passIndex < size);
return partsList;
}
@Test
public void test23() {
List<Integer> nums = new ArrayList<>(5);
for (int i = 0; i < 5; i++) {
nums.add(i);
}
toPart(nums, 3).forEach(System.out::println);
}
自动分页查询
@Test
public void selectBatch() {
// 1.查询总条数
int total = 5;
// 每次查询条数
int limit = 2;
// 已经查询的条数
int offset = 0;
do {
System.out.println("select * from a limit " + offset + "," + limit);
offset = limit + offset;
} while (offset <= total);
}
标签:异步,int,userIds,查询,add,分片,size
From: https://www.cnblogs.com/party-abu/p/17673541.html