当前位置:   article > 正文

Java操作Mongo数据库 依赖翻页-优化大数据量的翻页性能_java 优化mongodb翻页查询性能

java 优化mongodb翻页查询性能

大数量级mongo翻页Java代码

原文:mongo翻页Java代码

一、准备的基础环境

  1. 主要jar包依赖:
 <mongo.version>3.12.7</mongo.version>
 <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongo-java-driver</artifactId>
            <version>${mongo.version}</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. mongo compass可视化工具
    我这里大概40万数据,不算特别多
    我这里大概40万数据,不算特别多

    mongo采用的是mongoCollection:

private static MongoCollection<Document> mongoCollection = MongoDBTemplate.getCollection("索引名", "集合名");
  • 1

二、 传统skip 、limit 相同条件下遍历的性能对比

  1. mongo操作的dao代码图片:
    在这里插入图片描述

  2. 测试方法

/**
     * SkipAndLimit分页测试(20万数据12-14秒,40万数据大概43-50秒左右)------->也不推荐
     */
    @Test
    public void testMongoSkipAndLimitPage() {
        long startTime = System.currentTimeMillis()/1000;
        List<T> dataEntityList = new ArrayList<>(1000000);
        long totalSize = topicDao.getTotalSize();
        log.info("totalSize:{}",totalSize);
        int page = 1;
        int pageSize = 1000;
        int pages = (int) Math.ceil(totalSize / (double) pageSize);
        while (page <= pages) {
            List<T> byPage = topicDao.findDataWithSkip(page, pageSize);
            dataEntityList.addAll(byPage);
            page++;
            log.info("size:{}",dataEntityList.size());

//            if (page>200){
//                break;
//            }
        }
        log.info("spend time:{} 秒",System.currentTimeMillis()/1000-startTime);
    }

  • 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

上面的T改为自己的实体类

测试结果:

在这里插入图片描述
3. 结论:
传统的skip与limit翻页性能在数据量很大的时候,遍历的时候就会花费非常久的时间,我这里只有40万数据,就已经花了将近50秒钟,当数据量更大几个量级,那就有的等了。

二、方式二:每次翻页之前,查询到上一页的最后一条数据,然后从刚好比这条数据大的地方开始下一页遍历

  1. 主要mongo操作的dao代码图片
    在这里插入图片描述
    /**
     * 查询某一页最后一条数据的objectid
     * @return
     */

    public String findLastData(int page, int pageSize) {
        try {
            //url,commentId,name,userId,time,level,source,content,commentNum,likerNum,disLikerNum,parentCommentId
            Document document = mongoCollection.find().skip((page - 1) * pageSize).limit(pageSize).sort(new BasicDBObject("_id", 1)).first();
            String id = document.getObjectId("_id").toString();
//            log.info("id: {}",id);
            return id;
        }catch (Exception e){
            logger.error("mongo查询失败");
        }
        return null;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  1. 测试方法
/**
     * 依赖分页测试1(20万数据26-29秒,40万数据大概86-100秒左右)------->不推荐
     */
    @Test
    public void testMongoSomePage() {
        long startTime = System.currentTimeMillis()/1000;
        List<T> dataEntityList = new ArrayList<>(1000000);
        long totalSize = topicDao.getTotalSize();
        log.info("totalSize:{}",totalSize);
        int page = 1;
        int pageSize = 1000;
//        String lastId = "";
        int pages = (int) Math.ceil(totalSize / (double) pageSize);
        while (page <= pages) {
            List<T> byPage = topicDao.findByPage(page, pageSize);
            dataEntityList.addAll(byPage);
            log.info("size:{}",dataEntityList.size());
            page++;

//            if (page>200){
//                break;
//            }
        }
        log.info("spend time:{} 秒",System.currentTimeMillis()/1000-startTime);
    }
  • 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

上面代码中的T换成自己的实体类就行
测试图片如下:
在这里插入图片描述

  1. 结论
    这种方式是我第一次按照网上其他人的博客写的,但是很明显,每次翻页都需要查询一次上一页的最后一条objectid,本质上跟skip没什么区别,甚至多出了其他耗时的代码操作,最不推荐

三、大数据量依赖分页分页方式2:

  1. 翻页dao代码:

    /**
     * 依赖翻页mongo (速度快,推荐)
     * @param lastId 上一页最后一个 ObjectId
     * @param pageSize 每页大小
     * @return
     */
    public List<T> queryDataByPage(String lastId, int pageSize) {
        List<T> dataEntityList =new ArrayList<>(3000);
//        DBCursor dbObjects=null;
        MongoCursor<Document> cursor;
        BasicDBObject query=new BasicDBObject();
        if(StringUtils.isBlank(lastId)) {
            cursor = mongoCollection.find(query).sort(new BasicDBObject("_id",1)).limit(pageSize).iterator();
        } else {
            query.put("_id", new BasicDBObject(QueryOperators.GT,new ObjectId(lastId)));
            cursor = mongoCollection.find(query).limit(pageSize).sort(new BasicDBObject("_id",1)).iterator();
        }

        while (cursor.hasNext()){
            TdataEntity =new T();

            Document document = cursor.next();
            dataEntity.setUserId(document.getString("userId"));
            ......
            dataEntity.setId(document.getObjectId("_id").toString());
            dataEntityList.add(dataEntity);
        }
        cursor.close();
        return dataEntityList;
    }
  • 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

2.  **测试代码:**

```java
 /**
     * 依赖分页性能测试(20万数据4-6秒,40万数据大概10-12秒)---------------->推荐
     */
    @Test
    public void testMongoQueryByPage() {
        long startTime = System.currentTimeMillis()/1000;
        List<T> dataEntityList = new ArrayList<>(1000000);
        long totalSize = topicDao.getTotalSize();
        log.info("totalSize:{}",totalSize);
        int page = 1;
        int pageSize = 1000;
        //总页数
        long totalPage = totalSize/pageSize==0?totalSize/pageSize:totalSize/pageSize+1;
        String lastId = null;
        while (page <= totalPage) {
            List<T> byPage = topicDao.queryDataByPage(lastId,pageSize);
            if (!byPage.isEmpty()){
                dataEntityList.addAll(byPage);
                lastId = byPage.get(byPage.size()-1).getId();
                page++;
                log.info("size:{}",dataEntityList.size());

//                if (page>200){
//                    break;
//                }
            }

        }
        log.info("spend time:{} 秒",System.currentTimeMillis()/1000-startTime);
    }
  • 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

同样,上面代码中的T换成自己的实体类就行

翻页花费时间的截图如下:

在这里插入图片描述

  1. 结论:
    这里的逻辑跟第二种方法类似,只不过是每次翻页时直接返回最后一条数据,取其objectId(当然第一次的lastId为null,第一次翻页还是直接按照传统的skip与limit来翻页,当然如果你知道第一次翻页之前的objectId可以直接修改为传入就行),然后将其传入条件中,就可以达到更好的性能

我上面测试的都是以1000为一页的翻页大小,测试下来比之前的翻页快很多,当然如果你们有更好的方法,欢迎留言,留下代码,共同进步。

参考文献与博客:
【1】参考博客:亿级别记录的mongodb分页查询java代码实现

原文:mongo翻页Java代码

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/article/detail/56082
推荐阅读
相关标签
  

闽ICP备14008679号