../some-tips-for-paging
分页查询实践
Published:
pattern
君子不立危墙之下
作为后端开发来讲, 为用户端提供分页查询是最常规的事情了, 此处简单总结一下分页查询的个人实践.
从数据库说起
大部分情况下, 分页查询最终会映射到数据库查询, 以三个典型数据库为例, 看数据库如何支持分页查询.
MySql
select * from user limit 100,10
mysql 使用的 offset,limit 模式
Mongo
db.user.find().skip(100).limit(10)
mogno 同 mysql, 采用 offset, limit 模式
Redis
LRANGE user.key 100 110
redis 采用的也是类似 offset, limit 模式.
几种分页模式
Offset, limit 模式
直观的分页模式, 可无缝映射到数据库操作.
Page , size 模式
Spring 默认分页对象. 最终需要翻译到 offset,limit.
offset,limit = (page-1)*size, size
1,10 -> 0,10
10,10 -> 90,10
Anchor, limit 模式
对于数据量大的情况下, 大的offset 会有性能问题,此处不表, 通常会考虑以下查询语句
select * from user where id > 1000 limit 0,10
id > 1000 , id 作为锚点(anchor, 也必须是被索引的).
个人实践
- 统一分页对象, 从 API -> DAO, 大概长这样
class PageQuery {
Long start;
Long limit;
// ...
}
为什么采用 start,limit 作为参数? 此处用来统一offse,limit 和 anchor,limit 模式. 一般会用 long, timestamp 作为 anchor.
- 统一分页返回对象
class Page<T> {
private Boolean hasMore;
private Long nextStart;
private Long limit;
private List<T> result;
private Long total; // 可选, 一般情况不会提供此字段.
private Map<String, String> ext;
// ...
}
- 后端控制 limit. 分页的 limit 切不可由用户端控制(运营后台可适度放开). 必须由后端控制.
- 防止用户端随意传参
- 防止被抓包恶意调整参数
- 后端可针对特定业务进行透明的优化.
小结
简单总结了分页查询的个人实践.
- 采用 start,limit 方式分页
- 统一分页查询对象和分页返回对象
- 后端控制 limit 大小