1.場景:有大數據的數據需要放到首頁統計,一般就是聚合、分組之類的,按照年月日進行查詢和統計。如果數據量比較少,幾十萬數據 沒什么問題。但是隨着數據量的增多,查詢速度越來越慢。這個時候就需要去優化了~
剛開始自己的想法是這樣的:使用多線程的方式,因為查詢每天的數據量很少,那么是不是可以使用多線程的方式,每個線程查詢一天的,查詢一個月30天,就用30個線程,這樣速度會不會快些?
於是,用多線程的方式實現了下。代碼如下:
private ExecutorService executorService = new ThreadPoolExecutor(30,30,1, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>());
public List<Map> getCiServiceBadEvaNumStatistic(SAASIndexQuery saasIndexQuery) throws InvocationTargetException, IllegalAccessException { String startDate = saasIndexQuery.getStartDate(); String endDate = saasIndexQuery.getEndDate(); int days = DateUtil.getDatebetweenOfDayNum(DateUtil.parseDate(startDate,DateUtil.dateFormatPattern),DateUtil.parseDate(endDate,DateUtil.dateFormatPattern)); CompletionService<List<CiOrderStatisticSection>> completionService = new ExecutorCompletionService<List<CiOrderStatisticSection>>(executorService); List<CiOrderStatisticSection> allList = new ArrayList<>(); long start = System.currentTimeMillis(); logger.info("測試異步時間start:" + System.currentTimeMillis()); //CountDownLatch countDownLatch = new CountDownLatch(days); SAASIndexQuery everyDaySaas = new SAASIndexQuery(); BeanUtils.copyProperties(everyDaySaas,saasIndexQuery); for(int i = 0;i<days;i++){ everyDaySaas.setStartDate(DateUtil.afterNDay(saasIndexQuery.getStartDate(),i,DateUtil.dateFormatPattern)); everyDaySaas.setEndDate(DateUtil.afterNDay(everyDaySaas.getStartDate(),1,DateUtil.dateFormatPattern)); //countDownLatch.countDown(); int finalI = i; completionService.submit(new Callable<List<CiOrderStatisticSection>>() { @Override public List<CiOrderStatisticSection> call() throws Exception { //allList.addAll(biSaasCiDeviceDayExMapper.getCiServiceNegativeRate(saasIndexQuery)); //countDownLatch.countDown(); System.out.println("====="+ finalI +"====="); return biSaasCiDeviceDayExMapper.getCiServiceNegativeRate(saasIndexQuery); } }); } System.out.println("==============" + (System.currentTimeMillis()-start) + "毫秒"); long t = System.currentTimeMillis(); for (int i = 0;i<days;i++){ System.out.println("for循環耗時==============+"+i + (System.currentTimeMillis()-t) + "毫秒"); try { Future<List<CiOrderStatisticSection>> future = completionService.take(); List<CiOrderStatisticSection> ciList = future.get(); allList.addAll(ciList); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } long end = System.currentTimeMillis(); logger.info("測試異步時間end:" + (end-start) + "毫秒"); System.out.println("測試異步時間end:" + (end-start) + "毫秒"); }
測試后發現不對,使用多線程的take方式 每次都會有阻塞,這個阻塞一直沒明白是哪里阻塞了? 是線程池、LinkedBlockingDeque 還是for循環 take時候 阻塞了 一直沒明白,觀察的結果就是每次for循環都要差不多200多毫秒,30個循環要6s多。。。。額,算了 ,還沒有原來快呢
2.昨天換了種思路:直接從數據庫查詢時候做好控制。每次查詢先根據月份和年份,查詢出來id的最大值和最小值,之后sql里面查詢時候加上id在這個最大值和最小是區間內。大概思路是這樣:嗯,結果竟然可以。