数据区间按天拆分查询优化

发布时间:2023年12月18日

行驶数据查询和导出优化:Ymatrix查询一天数据会很快在1秒内,区间查询时间超过7天效率会下降到7秒+。

所以在区间日期查询行驶数据时做优化,将区间日期拆分为一天去查ymatrix提升查询效率

如查询条件 2023-11-28 16:41:11 - 2023-12-05 16:41:11,pageNum=1,pageSize=10

开始时间结束时间总数offsetpageSize 
执行时间拆分如下? 、 并发查询每一条时间总条数据(查询效率500ms以内) 
startTime='2023-12-04 16:41:11', endTime='2023-12-05 16:41:11' , initCount=4 
startTime='2023-12-03 16:41:11', endTime='2023-12-04 16:41:11' , initCount=23 
startTime='2023-12-02 16:41:11', endTime='2023-12-03 16:41:11' , initCount=18 
startTime='2023-12-01 16:41:11', endTime='2023-12-02 16:41:11' , initCount=20 
startTime='2023-11-30 16:41:11', endTime='2023-12-04 16:41:11' , initCount=10 
startTime='2023-11-29 16:41:11', endTime='2023-11-30 16:41:11' , initCount=5 
startTime='2023-11-28 16:41:11', endTime='2023-11-29 16:41:11' , initCount=1  
计算页码归属日期条件 
i=1, 
startTime='2023-12-04 16:41:11', endTime='2023-12-05 16:41:11', initCount=4, count=4, offset=0, pageSize=4 
startTime='2023-12-03 16:41:11', endTime='2023-12-04 16:41:11', initCount=23, count=17, offset=0, pageSize=6 
i=2, 
startTime='2023-12-03 16:41:11', endTime='2023-12-04 16:41:11', initCount=23, count=17, offset=6, pageSize=10 
i=3, 
startTime='2023-12-03 16:41:11', endTime='2023-12-04 16:41:11', initCount=23, count=7, offset=16, pageSize=7 
startTime='2023-12-02 16:41:11', endTime='2023-12-03 16:41:11', initCount=18, count=15, offset=0, pageSize=3 
i=4, 
startTime='2023-12-02 16:41:11', endTime='2023-12-03 16:41:11', initCount=18, count=15, offset=3, pageSize=10 
i=5, 
startTime='2023-12-02 16:41:11', endTime='2023-12-03 16:41:11', initCount=18, count=5, offset=13, pageSize=5 
startTime='2023-12-01 16:41:11', endTime='2023-12-02 16:41:11', initCount=20, count=15, offset=0, pageSize=5 
i=6, 
startTime='2023-12-01 16:41:11', endTime='2023-12-02 16:41:11', initCount=20, count=15, offset=5, pageSize=10 
i=7, 
startTime='2023-12-01 16:41:11', endTime='2023-12-02 16:41:11', initCount=20, count=5, offset=15, pageSize=5 
startTime='2023-11-30 16:41:11', endTime='2023-12-01 16:41:11', initCount=10, count=5, offset=0, pageSize=5 
i=8, 
startTime='2023-11-30 16:41:11', endTime='2023-12-01 16:41:11', initCount=10, count=5, offset=5, pageSize=5 
startTime='2023-11-29 16:41:11', endTime='2023-11-30 16:41:11', initCount=5, count=5, offset=0, pageSize=5 
i=9, 
startTime='2023-11-28 16:41:11', endTime='2023-11-29 16:41:11', initCount=1, count=1, offset=0, pageSize=1 
public class LimitCache {
    private String startTime;
    private String endTime;
    //剩余条数
    private int count;
    //总条数
    private int initCount;

    //查询数据库的起始数据
    private int offset;
    //页数
    private int pageSize;
	//第几页
    private int index;

    public void setInitCount(int initCount) {
        this.initCount = initCount;
    }

    public void setCount(int count) {
        this.count = count;

        if (this.initCount == 0){
            this.initCount = count;
        }
        if (initCount <= count ){
            this.initCount = count;
        }
    }
}

public class QueryVehicleDataByVinListDomain {
    private String vin;
    private String startTime;
    private String endTime;
    private Integer pageNo;
    private Integer pageSize;
    private AtomicInteger atomicInteger = new AtomicInteger();
    private ThreadPoolExecutor poolExecutor = SweetThreadPoolExecutor.getExecutor(5, 1000);

    private Cache<String, Integer> countCache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build();

    public QueryVehicleDataByVinListDomain(String vin, String startTime, String endTime, Integer pageNo, Integer pageSize) {
        this.vin = vin;
        this.startTime = startTime;
        this.endTime = endTime;
        this.pageNo = pageNo;
        this.pageSize = pageSize;
        atomicInteger.getAndIncrement();
    }

    public PageInfo<NewEnergyVehicleDataDto> handle() {
        List<LimitCache> tcs = queryTotal(time(startTime, endTime));
        int pages = (int) Math.ceil((double) (tcs.stream().map(LimitCache::getCount).reduce(0, Integer::sum)) / pageSize);
        int count = tcs.stream().map(LimitCache::getCount).reduce(0, Integer::sum);
        NewEnergyVehicleDataMapper newEnergyVehicleDataMapper = SpringApplicationUtils.getBean(NewEnergyVehicleDataMapper.class);

        PageInfo<NewEnergyVehicleDataDto> retPage = new PageInfo<>();
        if (count > 0) {
            List<List<LimitCache>> lists = doGetList(tcs);
            List<NewEnergyVehicleDataEntity> list = Lists.newArrayList();
            List<LimitCache> cacheList = lists.get(pageNo - 1);
            log.info("执行分页查询 list.index【{}】,pageNo【{}】,LimitCache 【{}】 ", pageNo - 1, pageNo, cacheList.toString());
            cacheList.stream().forEach(v -> {
                List<NewEnergyVehicleDataEntity> list2 = newEnergyVehicleDataMapper.selectNewEnergyVehicleDataList(v.getStartTime(), v.getEndTime(), Arrays.asList(vin), v.getOffset(), v.getPageSize());
                list.addAll(list2);
            });

            retPage.setList(new ConvertNewEnergyVehicleDomain(list).handle());
            retPage.setTotal(count);
            retPage.setPages(pages);
            retPage.setPageNum(pageNo);
            retPage.setPageSize(pageSize);
        }
        return retPage;

    }

    //缓存
    private List<List<LimitCache>> doGetList(List<LimitCache> tcs) {
        return handleTimeToPages(tcs, pageSize);

    }


    private List<List<LimitCache>> handleTimeToPages(List<LimitCache> list, int pageSize) {
        List<List<LimitCache>> ret = Lists.newArrayList();

        List<LimitCache> newList = Lists.newArrayList();
        for (LimitCache lc : list) {
            LimitCache l = new LimitCache();
            BeanUtils.copyProperties(lc, l);
            newList.add(l);
        }
        int index = 1;
        int offset = 0;
        while (CollectionUtils.isNotEmpty(newList) && index <= list.size()) {
            List<List<LimitCache>> limitCaches = doHandleTimeToPages(newList, pageSize, offset);
            ret.addAll(limitCaches);
            //获取最后一条记录取 offset
            LimitCache limitCache = limitCaches.get(limitCaches.size() - 1).get(limitCaches.get(limitCaches.size() - 1).size() - 1);
            //时间上一页还有剩余,则是需要记录offset
            if (limitCache.getCount() != 0 && (limitCache.getOffset() + limitCache.getPageSize()) < limitCache.getInitCount()) {
                offset = limitCache.getPageSize();
            } else {
                offset = 0;
            }
            index++;
        }

        return ret;
    }
private List<List<LimitCache>> doHandleTimeToPages(List<LimitCache> list, int pageSize, int offset) {
        Iterator<LimitCache> iterator = list.iterator();
        List<List<LimitCache>> ret = Lists.newArrayList();
        while (iterator.hasNext()) {
            LimitCache limitCache = iterator.next();
            int count = limitCache.getCount();
            //如果当前行不满一页
            if (count < pageSize) {
                int index = atomicInteger.getAndIncrement();
                List<LimitCache> limitCaches = Lists.newArrayList();
                limitCache.setPageSize(count);
                limitCache.setIndex(index);
                limitCache.setOffset(offset);
                limitCaches.add(limitCache);
                iterator.remove();
                limitCaches.addAll(getLimitCaches(list, pageSize, count, index));

                ret.add(limitCaches);
                return ret;
                //当前行大于1页
            } else {
                iterator.remove();
                int pages = (int) Math.ceil((double) limitCache.getCount() / pageSize);
                for (int i = 1; i <= pages; i++) {
                    int index = atomicInteger.getAndIncrement();
                    List<LimitCache> limitCaches = Lists.newArrayList();
                    int cnt = limitCache.getCount();
                    LimitCache lc = new LimitCache();
                    BeanUtils.copyProperties(limitCache, lc);
                    int os = ((i - 1) * pageSize) + offset;
                    lc.setOffset(os);
                    //不满足则需要借
                    if (cnt < pageSize) {
                        lc.setPageSize(cnt);
                        lc.setIndex(index);
                        limitCaches.add(lc);
                        limitCaches.addAll(getLimitCaches(list, pageSize, cnt, index));
                        ret.add(limitCaches);
                    } else {
                        lc.setIndex(index);
                        lc.setPageSize(pageSize);
                        limitCaches.add(lc);
                        ret.add(limitCaches);
                    }
                    limitCache.setCount(limitCache.getCount() - pageSize);
                }
                return ret;
            }
        }
        return ret;
    }

    /**
     * 不满足pageSize则一直取
     *
     * @param list
     * @param pageSize
     * @param count
     * @param index
     * @return
     */
    private List<LimitCache> getLimitCaches(List<LimitCache> list, int pageSize, int count, int index) {
        List<LimitCache> ret = Lists.newArrayList();
        Iterator<LimitCache> iterator = list.iterator();
        int count2 = count;
        while (iterator.hasNext()) {
            LimitCache limitCache = iterator.next();
            count2 = limitCache.getCount() + count2;
            //如果当前行不满一页
            if (count2 < pageSize) {
                limitCache.setPageSize(limitCache.getCount());
                limitCache.setOffset(0);
                limitCache.setIndex(index);
                ret.add(limitCache);
                iterator.remove();
                //刚好满足pageSize
            } else if (count2 == pageSize) {
                //余数
                limitCache.setPageSize(limitCache.getCount());
                limitCache.setOffset(0);
                limitCache.setIndex(index);
                iterator.remove();
                ret.add(limitCache);
                break;
                //满足超出,则借用下一个日期
            } else {
                //需要借用多少
                int c = (pageSize - (count2 - limitCache.getCount()));
                limitCache.setPageSize(c);
                limitCache.setCount(limitCache.getCount() - c);
                limitCache.setOffset(0);
                limitCache.setIndex(index);
                LimitCache lc = new LimitCache();
                BeanUtils.copyProperties(limitCache, lc);
                ret.add(lc);
                break;
            }
        }
        return ret;

    }

    private List<LimitCache> queryTotal(List<LimitCache> list) {
        List<LimitCache> ret = Lists.newArrayList();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        RequestContextHolder.setRequestAttributes(servletRequestAttributes, true);//设置子线程共享
        //这里创建线程池查询没有java8list多线程,是因为java8创建的线程数太少影响效率
        NewEnergyVehicleDataMapper newEnergyVehicleDataMapper = SpringApplicationUtils.getBean(NewEnergyVehicleDataMapper.class);
        List<Future<Map<String, Integer>>> futures = Lists.newArrayList();
        int i = 0;
        for (LimitCache lc : list){
            if (i == 0){
                //最新日期总数会变化,所以不做缓存每次都查最新
                poolExecutor.submit(() -> {
                    Integer count = newEnergyVehicleDataMapper.selectNewEnergyVehicleDataCount(lc.getStartTime(), lc.getEndTime(), Arrays.asList(vin));
                    lc.setCount(count);
                });
                i++;
                continue;
            }
            Future<Map<String, Integer>> futureMap = poolExecutor.submit(() -> {
                String key = vin + lc.getStartTime() + lc.getEndTime();
                Integer count = countCache.getIfPresent(key);
                if (count == null) {
                    count = newEnergyVehicleDataMapper.selectNewEnergyVehicleDataCount(lc.getStartTime(), lc.getEndTime(), Arrays.asList(vin));
                    countCache.put(key, count);
                }
                Map<String, Integer> countMap = Maps.newLinkedHashMapWithExpectedSize(1);
                countMap.put(lc.getStartTime() + lc.getEndTime(), count);
                //查询数据库
                lc.setCount(count);
                return countMap;
            });
            futures.add(futureMap);
            i++;
        }

        Map<String, Integer> countMap = Maps.newHashMap();
        for (Future<Map<String, Integer>> future : futures) {
            try {
                countMap.putAll(future.get());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        for (LimitCache lc : list) {
            LimitCache newLc = new LimitCache();
            BeanUtils.copyProperties(lc, newLc);
            Integer cnt = countMap.get(lc.getStartTime() + lc.getEndTime());
            if (cnt != null){
                newLc.setCount(cnt);
            }
            ret.add(newLc);
        }
        return ret;


//        list.get(0).setCount(6);
//        list.get(1).setCount(3);
//        list.get(2).setCount(2);
//        list.get(3).setCount(8);
//        list.get(4).setCount(1);
//        list.get(5).setCount(12);
//        list.get(6).setCount(8);
//        return list;

//        Random random = new Random();
//        List<LimitCache>  ret = Lists.newArrayList();
//        for (LimitCache lc : list){
//            LimitCache newLc = new LimitCache();
//            //查询数据库
//            lc.setCount(random.nextInt(30));
//            BeanUtils.copyProperties(lc,newLc);
//            ret.add(newLc);
//        }
//        return ret;


    }


    /**
     * 根据数据的排序规则
     * 现在是降序,从大到小,
     * 如果需要升序,则需要改下代码
     * @param startTime
     * @param endTime
     * @return
     */
    private List<LimitCache> time(String startTime, String endTime) {
        DateTimeFormatter format = DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_STRING);
        List<LimitCache> times = Lists.newArrayList();
        String sd = startTime.substring(0, 10);
        String ed = endTime.substring(0, 10);
        LocalDate startDate = LocalDate.parse(sd, format);
        LocalDate endDate = LocalDate.parse(ed, format);
        LimitCache slc = new LimitCache();
        slc.setStartTime(ed + " 00:00:00");
        slc.setEndTime(endTime);
        times.add(slc);

        long numOfDays = ChronoUnit.DAYS.between(startDate, endDate);

        for (int i = 1; i < numOfDays; i++) {
            LocalDate currentDate = endDate.minusDays(i);
            LimitCache lc = new LimitCache();
            lc.setStartTime(currentDate.format(format) + " 00:00:00");
            lc.setEndTime(currentDate.format(format) + " 23:59:59");
            times.add(lc);
        }
        LimitCache elc = new LimitCache();
        elc.setStartTime(startTime);
        elc.setEndTime(sd + " 23:59:59");
        times.add(elc);
        return times.stream().sorted(Comparator.comparing(LimitCache::getEndTime).reversed()).collect(Collectors.toList());
    }

文章来源:https://blog.csdn.net/qq1010267837/article/details/135012141
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。