Java中Mongodb的分页优化

问题

在Java中使用mongodb的MongoTemplate进行分页时,一般的策略是使用skip+limit的方式,但是这种方式在需要略过大量数据的时候就显得很低效(即skip趋向于变大)。

而且, 在数据查询语句中使用到了SORT排序的时候,mongo很容易内存溢出,报出如下错误:

lan executor error during find: Overflow sort stage buffered data usage of 33568573 bytes exceeds internal limit of 33554432 bytes

sort会将当前搜索出来的数据放入缓存,进行排序,如果一次性查询的输出量太大,超过33554432bytes,即报内存溢出异常

这种情况下要么去掉sort,要么减少一次性查询的输出量。

但是,sort是业务需求,能做的优化就是从一次性查询的输出量上想办法。

方法

目前我实践的有两种分页方法:

一、将上一页最后一条数据的时间戳作为搜索条件。这样做有一个局限,只能在连续跳页中使用,如果是间断式跳页,就无法满足。

二、如果skip略过量超过5000条,将搜索结果按5000条进行第一层分页,每次获取5000条数据中的最后一条数据的时间戳,用作下一次的查询条件,每次循环skip略过量就减少5000,循环直至skip少于5000条,然后再skip,代码如下:

            int pageSkip = 5000;
            if(s.getOffset()>pageSkip){
                int offset = s.getOffset();
                int cycleCount = s.getOffset()/pageSkip;
                //每次查询5000条数据
                long lastUpdateTime = 0;
                while(cycleCount>0){
                    //分段查询
                    Query queryNew = getDBComponent().getQueryBuilder(s.getClass()).buildQuery(s);
                    queryNew.addCriteria(Criteria.where("dr").is(BaseObject.DR_YES));//dr 软删除下可见的数据
                    queryNew.with(new Sort(Sort.Direction.DESC,"lastUpdateTime"));
                    queryNew.skip(pageSkip);
                    if(lastUpdateTime!=0){
                        queryNew.addCriteria(Criteria.where("lastUpdateTime").lt(lastUpdateTime));
                    }
                    BaseObject baseObject = (BaseObject) getDBComponent().getMongoDao().findOne(queryNew);
                    lastUpdateTime = baseObject.getLastUpdateTime();
                    cycleCount--;
                    offset-=pageSkip;
                }
                query.skip(offset);
                query.addCriteria(Criteria.where("lastUpdateTime").lt(lastUpdateTime));
            }else{
                query.skip(s.getOffset());
            }

猜你喜欢

转载自my.oschina.net/u/3638962/blog/1611287