最常见的分页采用的是skip+limit这种组合方式,这种方式对付小数据倒也可以,但是对付上几百上千万的大数据,只能力不从心,skip如果跳过大量的数据会很慢,并且会越查越慢,针对这一情况,可以通过条件查询+排序+限制返回记录,即 边查询,边排序,排序之后,抽取上一页中的最后一条记录,作为当前分页的查询条件,从而避免了skip效率低下的问题。
代码如下:
/**
* 大数据量排序方式分页获取数据
* @param page 页码
* @param pageSize 每页条数
* @param collectionName 表名
* @param totalCon 查询条件汇总 ,在执行之前需要判断是否需要存放最后一条的ID【totalCon.put("_id", new BasicDBObject(QueryOperators.GT, lastStr))】,当_id是自动生成的时候,不要用转换后的_id
* @param fields 输出指定字段
*/
public DBCursor largePageList(int page, int pageSize, String collectionName, BasicDBObject totalCon, BasicDBObject fields) {
try {
return mongoTemplate.getCollection(collectionName).find(totalCon,fields).sort(new BasicDBObject("_id", 1)).limit(pageSize);
} catch (Exception e) {
LoggerUtil.error("***大数据量数据分页查询失败,collectionName=" + collectionName, e.getCause().getMessage());
}
return null;
}
调用代码示例:
/**
* 执行方法
*/
public void exeMethod() {
long start = System.currentTimeMillis(); // 记录起始时间
int lastExeNum = 0;
int pageSize = 500;//每次查询的记录数
try {
//拼装条件,30天<timestamp<7天
BasicDBObject totalCon = new BasicDBObject();
totalCon.put("timestamp", new BasicDBObject("$gte",
DateUtils.dateToStr(DateUtils.getComputeTime(new Date(),Calendar.DAY_OF_MONTH,longDay), DateUtils._yMdHms)).append("$lte",
DateUtils.dateToStr(DateUtils.getComputeTime(new Date(),Calendar.DAY_OF_MONTH,-7), DateUtils._yMdHms)));
totalCon.put("isFrom", Yes);
//输出指定字段
BasicDBObject fields = new BasicDBObject();
fields.put("_id", 1);
fields.put("timestamp", 1);
DBCursor cursorless = null;
Map<String, String> map = null;
DBObject obj = null;
for(int j=0;j<100;j++){
cursorless = null;
obj = null;
map = null;
TimeUnit.SECONDS.sleep(10);
String lastStr ="";//上一页最后一条数据的 _id
String table = String.format(DBKeys.jruseractive, j);
if(totalCon.containsField("_id")){
totalCon.removeField("_id");
}
long count= mongoDao.count(new BasicQuery(totalCon), table);
int page = ((int)count + (pageSize - 1)) / pageSize;
for(int i=1;i<=page;i++){
cursorless = null;
obj = null;
map = null;
TimeUnit.MILLISECONDS.sleep(10);
//上一页最后一条数据,如果不为空,就加上,作为查询下一页的条件
if (!"".equals(lastStr)) {
totalCon.put("_id", new BasicDBObject(QueryOperators.GT, lastStr));
}
cursorless = mongoDao.largePageList(i,pageSize,table,totalCon,fields);
while (cursorless.hasNext()) {
obj = null;
map = null;
obj = cursorless.next();
if(null != obj && obj.get("_id")!=null){
String _id=obj.get("_id")+"";
String timestamp=obj.get("timestamp")+"";
/**-------处理后续动作----------*/
/**-------处理后续动作----------*/
}
}
//获取一次分页中最后一条记录的"_id",然后作为查询条件传入到下一条执行语句中
if (null != obj) {
lastStr = obj.get("_id").toString();
LoggerUtils.info(getClass(), "**************最后一条数据的唯一索引(id):"+lastStr);
}
}
}
} catch (Exception e) {
LoggerUtils.error(getClass(), e.getMessage(),e);
}
}