• 批量循环查询


    1、rpc批量查询

        private List<DTO> query(String code, Integer type) {
    
            List<DTO> resultList = new ArrayList<>();
            List<DTO> skuList;
      
            //01.构造req
            Req request = buildTRequest(code, type);
            Response response;
            int fetchedCount = 0;
            int maxCycle = 1;
            boolean needMoreFetch = true;
            while (maxCycle <= 1000) {
                maxCycle++;
                try {
                    response = skuGateway.query(request);
                } catch (Exception e) {
                    throw new GatewayException(1,
                            String.format("获取sku失败 code:[%s]", code), e);
                }
                skuList = response.getData();
                
                if (CollectionUtils.isNotEmpty(skuList)) {
                    resultList.addAll(skuList);
                    fetchedCount += skuList.size();
                }
    
                if (total <= fetchedCount) {
                    needMoreFetch = false;
                } else {
                    request.setOffset(fetchedCount);
                }
            }
            return resultList;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    2、200、200条查询db数据

    • eg1
    private void query(Request request) {
    
            int page = 1;
            List<DO> dOList = query(request, page);
            while (CollectionUtils.isNotEmpty(dOList) && page <= 1000) {//一次200,循环1000次,就是20w的数据量,肯定够了
                //处理数据
                judgeSameTask(dOList);
                if (200 > dOList.size()) {
                    break;
                }
                page++;
                dOList = query(request, page);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • eg2
    private List<Info> batchQuery(Request request) {
            List<Info> result = new ArrayList<>();
            int page = 1;
            List<Info> infos = query(request, page);
            while (CollectionUtils.isNotEmpty(infos) && page <= 1000) {//一次200,循环1000次,就是20w的数据量,肯定够了
                result.addAll(infos);
                if (200 > infos.size()) {
                    break;
                }
                page++;
                infos = query(request, page);
            }
            return totalSkuStockList;
        }
    
    
    private List<ReturnPlanTaskDO> query(Request request, int page) {
    
            //01.构建查询条件
            XxxDOExample example = buildDOExample();
    
            //02.分页参数
            example.limit((page - 1) * 200, 200);
    
            //03.查询
            return myService.query(example);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • eg3
        private List<Info> batchQuery(TRequest request) {
            List<Info> result = new ArrayList<>();
            int page = 1;
            List<Info> infoList = query(request, page);
            while (CollectionUtils.isNotEmpty(infoList) && page <= 1000) {//一次200,循环1000次,就是20w的数据量,肯定够了
                result.addAll(infoList);
                if (200 > skuStockSaleInfos.size()) {
                    break;
                }
                page++;
                infoList = query(request, page);
            }
            return result;
        }
    
        private List<Info> query(TRequest request, int page) {
            //01.构建查询条件
            Paging paging = new Paging();
            paging.setOffset((page - 1) * 200);
            paging.setLimit(200);
            request.setPaging(paging);
    
            //02.查询
            TResponse response = skuService.query(request);
            if (response != null && response.getCode() == 0) {
                return response.getInfoList();
            } else {
                return Collections.emptyList();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • eg4
    List<DO> result = Lists.newArrayList();
    boolean loop = true;
    long id = 0L;
    do {
        XxxDOExample example = new XxxDOExample();
        example.limit(200);
        example.setOrderByClause("id asc");
        XxxDOExample.Criteria criteria = example.createCriteria();
        criteria1.andValidEqualTo(Boolean.TRUE);
        criteria1.andIdGreaterThan(id);
        List<DO> selectByExample = myMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(selectByExample)) {
        result.addAll(selectByExample);
        int size = selectByExample.size();
        if (size < 200) {
            loop = false;
        } else {
            id = selectByExample.get(size - 1).getId();
        }
    } while (loop);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    第一次查询0-100,数据。(过滤或者处理一下这100条数据)后,存入list中,fetchCount = 100,

    第二次查询100-200。(过滤或者处理一下这100条数据)后,存入list中,fetchCount = 200,

    ···

    直到第10次处理完,fetchCount == total(1000)了,needFalse = false,停止查询

    补充:为什么采用这种,每次查询100条,(处理或不处理)存入list,直到全部1000条都(处理或不处理)存入list。而不是直接一次查询出这1000条数据

    解:因为如果你不查询一次,你根本就不知道数据库中有1000条满足条件的数据。所以,你也可以先查询一次limit offset(0-1)查出total = 1000,此时你再执行sql查询page(0-1000)一次全部查出来放入list

    limit 20000 , 10:从第20001行数据开始查找,查找10条(20001、20002、····200010)=》 where id 〉 20000 limit 0 ,10。PageModel即父类RowBounds(mysql中的)即这种形式limit、offset

    limit 10 offset 3 :(从第4行开始查找,找10条数据),即4、5、6、···13。

    
          
            limit ${offset}, ${rows}    偏移量、多少条
          
          
            limit ${rows}
          
        
        这里limit ${offset}, ${rows}   对比 limit 20000 , 10
        即offset是偏移量,从第20001开始查询,查10条。 这里是limit 0,1000 从第一条开始查查询1000条
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    • eg5
    return Lists.partition(skuIds, 200).stream().map(skus -> {
    	XxxDOExample example = new XxxDOExample();
    example.createCriteria().andSkuIdIn(skus)
                        .andValidEqualTo(Boolean.TRUE);
                return example;
            }).map(example -> myMapper.selectByExample(example))
                    .reduce((list1, list2) -> {
                        list1.addAll(list2);
                        return list1;
             }).orElse(Lists.newArrayList());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3、分页查询注意事项

    只要使用分页查询,必须加上order by

    1、原因

    不使用order by,分页查询的数据不准确

    • 背景:

      select查询,如果不走二级索引查询,查询结果默认是按照主键id,正序排序;

      如果走了二级索引,则结果默认按二级索引排序展示

    • 问题复现

      select limit 0,5,使用了二级索引A进行查询,则结果按照索引A正序排序,为:7,8,9,1,2;

      又进行了select 5,10查询第二页;

      此时,因为数据库原因(主从切换,原本该走从查询的,现在走主查询了),或数据量变化(原本数据量级该走A索引查询的,现在走B索引查询了)

      select limit 5,5,使用了二级索引B进行查询,则结果按照索引B正序排序,为:11,12,13,14,2;导致id = 2的数据,在第一页 和 第二页分页查询结果中都出现了!!!甚至会导致数据丢失

    2、解:

    分页查询一定使用order by

    3、SOP

    3.1 分页查询全量数据(200、200、200 —)

    • 无脑order by id asc即可

    • 原因:

      此时如果order by 字段a,会有以下问题

      • 字段a,不是联合索引一员,导致走不到索引

      • 字段a,是联合索引一员,但是,中间断了x_y_z_a,但是本次查询条件仅有x_y ,order by a,也会使索引失效

      • 字段a,是联合索引一员,且连续,能走到索引,但是order by a字段,a字段有很多相同的数据。比如a字段为仓id

        select order by a ,limit 0, 5 ,结果为7,8,9,1,2

    ​ select order by a ,limit 5, 5 ,结果为2,11,12,13,14

    ​ 原因就是a字段有很多相同的数据,order by a,前后两页也有可能有相同数据

    ​ 比如联合索引为valid_poiId,select * from table where valid = 1 limit 0,200这个时候查出来的数据都是valid = 1的,因此查询结果会按照联合索引中的第二个字段poiId正序排序的!!!

    即生效sql实际上为select * from table where valid = 1 order by poiId asc limit 0,200

    问题:当poi_id有序增长时,id的增长并不有序,甚至可能跨度很大!!!,导致翻页时,如果使用了granThanId方式,取最后一条数据的id可能跳跃很大,导致漏数据。

    复现:

    查询结果 poiId id

    ​ 1 10009577 777

    ​ 2 10001014 77777777

    这样即使查询出来的两条数据按poiId排序挨在一起,但是id却跨度很大很大。上一次granthanId的id为776,不会丢数据。这一次granThanid的id为77777777,id > 77777777,这样777- 77777777中间很多id的数据都没查出来!!!相当于丢数据了

    所以,此时必须添加一个能确定顺序的索引,即order by a asc,id asc 。不如,直接order by id

    3.2 分页查询全量数据,建议使用greathanId

    3.3 如果是页面分页查询某一页的数据,而且需要字段a排序展示,则order by a asc,id asc

    • 原因:如果直接order by id,则查询出来的几条数据,不是按a字段排序的,可能不符合要求(a字段为销量,order by id查询出来的几条数据,销量可能不是最高的前几条)
    example.setOrderByClause("poi_id asc, create_at asc");
    
    • 1
  • 相关阅读:
    STL中map的成员函数insert的返回值
    Media Encoder 2024 for Mac媒体编码器安装教程ME2024安装包下载
    JavaScript 编程的内部方法有哪些?
    JavaScript笔记
    【数据结构初阶】顺序表
    FFmpeg进阶:生成视频的缩略图
    瑞吉外卖 新增员工功能
    迅雷不限速破解方法
    Transformer模型架构笔记
    【无标题】
  • 原文地址:https://blog.csdn.net/tmax52HZ/article/details/133252893