如何在spring中使用多线程完成分页接口的两次查询数据库?

通常情况下,分页接口一般会查询两次数据库,第一次是获取具体数据,第二次是获取总的记录行数,然后把结果整合之后,再返回。
例如:

select id,name from user limit 20;  // 查询数据
select count(*) from user;  // 查询数量

现在count(*) 查询数据效率很慢,想使用spring多线程完成性能优化,如何实现?

阅读 6.3k
8 个回答

SELECT SQL_CALC_FOUND_ROWS * from user; SELECT FOUND_ROWS()

像mybatis的话,你就得自己去改造插件去做异步了,说难不难,说易不易吧

count()很慢 你用多线程最快也就跟count()的速度一样啊 解决不了问题
应该从sql角度优化下或者加缓存来解决

count() 理论上只要索引合理,是没太多方案在sql数据库索引层面解决问题了而且使用count(),还特别慢的话,如果业务对总数不敏感的话,你可以考虑使用redis,对count(*)的结果进行缓存可以隔一两个小时失效同步一次数据,这样做虽然数据会出现延迟不过会在可接受范围内。如果要求敏感的话,你可以进行增量处理,先缓存数据库数据,然后没增加一个数据,就更新redis缓存,这样做的话,就算更新频繁也只会出现少量的用户量偏差,不特别影响数据观测

分页查询,必须知道总数才能进行分页。所以必须根据count()的结果来进行分页。
所以不可能通过异步的方式来实现这个业务,通常的做法都是通过优化sql来提升查询速度。

MyBatis-Plus版:
使用示例:

demoService.pageParallel(new Page<>(1, 10), Wrappers.lambdaQuery(DemoEntity.class));

代码实现:

private static final ExecutorService CACHED_THREAD_POOL_EXECUTOR = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("page-count-%d").build());

@SneakyThrows
@Override
public <E extends IPage<T>> E pageParallel(E page, Wrapper<T> queryWrapper) {
    CompletableFuture<Long> countFuture = CompletableFuture.supplyAsync(() -> count(queryWrapper), CACHED_THREAD_POOL_EXECUTOR);
    page.setRecords(page(new Page<>(page.getCurrent(), page.getSize(), false), queryWrapper).getRecords());
    page.setTotal(countFuture.get());
    return page;
}
新手上路,请多包涵

有create_date吗? 只差当天的数量, 当天以前的数量放redis里即可,

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题