MongoDB分页实现方式对比:PageRequest vs Skip/Limit
一、基本概念
1.1 PageRequest分页
PageRequest是Spring Data提供的分页实现,它是基于页码的分页方式(Page-based pagination)。
new PageRequest(page, size)
// page: 页码,从0开始
// size: 每页大小
1.2 Skip/Limit分页
Skip/Limit是MongoDB原生的分页方式,它是基于偏移量的分页(Offset-based pagination)。
query.skip(offset).limit(size)
// offset: 跳过的记录数
// size: 获取的记录数
二、主要区别
2.1 使用方式
- PageRequest:
// 获取第一页,每页10条
Pageable pageable = new PageRequest(0, 10);
// 获取第二页,每页10条
Pageable pageable = new PageRequest(1, 10);
- Skip/Limit:
// 获取前10条
query.skip(0).limit(10);
// 获取第11-20条
query.skip(10).limit(10);
2.2 参数计算
- PageRequest:
page = pageNumber - 1 // pageNumber从1开始
size = pageSize
- Skip/Limit:
offset = (pageNumber - 1) * pageSize
limit = pageSize
2.3 适用场景
PageRequest适用场景:
- 需要与Spring Data框架深度集成
- 需要获取分页的额外信息(总页数、是否是最后一页等)
- 数据量较小,页码跨度不大的场景
- 用户界面基于页码导航的场景
Skip/Limit适用场景:
- 需要更灵活的分页控制
- 数据量大,但主要关注连续分页的场景
- 无限滚动加载的场景
- 需要优化性能的场景
三、性能考虑
3.1 PageRequest的性能特点
优点:
- 与Spring Data完美集成
- 提供丰富的分页信息
- 代码可读性好
缺点:
- 大页码时性能较差
- 内存占用相对较高
- 不适合大数据量分页
3.2 Skip/Limit的性能特点
优点:
- 实现简单直接
- 内存占用低
- 适合大数据量分页
缺点:
- skip值较大时性能会下降
- 不提供总页数等信息
- 需要自行处理边界情况
四、最佳实践建议
4.1 选择建议
小型应用,数据量不大:
- 推荐使用PageRequest,开发更便捷
大型应用,数据量大:
- 推荐使用Skip/Limit,性能更好
- 考虑使用游标或时间戳分页
4.2 性能优化建议
- 添加适当的索引
- 避免大的偏移量
- 考虑使用游标分页
- 合理设置每页大小
4.3 代码示例
PageRequest方式:
public List<MetadataPO> findByPage(String appId, int page, int size) {
Pageable pageable = new PageRequest(page, size);
Query query = new Query().with(pageable);
return mongoTemplate.find(query, MetadataPO.class);
}
Skip/Limit方式:
public List<MetadataPO> findByOffset(String appId, int offset, int size) {
Query query = new Query();
query.skip(offset).limit(size);
return mongoTemplate.find(query, MetadataPO.class);
}
五、总结
PageRequest和Skip/Limit各有优势,选择时需要考虑:
- 数据量大小
- 性能要求
- 业务场景
- 开发便利性
实际应用建议:
- 数据量<10万,用户习惯页码翻页:选择PageRequest
- 数据量>10万,或需要无限滚动:选择Skip/Limit
- 数据量>100万:考虑使用游标分页
性能优化核心:
- 合理使用索引
- 避免大偏移量
- 控制每页数据量
- 考虑缓存策略