../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, 也必须是被索引的).

个人实践

  1. 统一分页对象, 从 API -> DAO, 大概长这样
class PageQuery {
  Long start; 
  Long limit;
  // ...
}

为什么采用 start,limit 作为参数? 此处用来统一offse,limit 和 anchor,limit 模式. 一般会用 long, timestamp 作为 anchor.

  1. 统一分页返回对象
class Page<T> {
  private Boolean hasMore;
  private Long nextStart;
  private Long limit;
  private List<T> result;
  private Long total;  // 可选, 一般情况不会提供此字段.
  private Map<String, String> ext;
  
  // ...
}
  1. 后端控制 limit. 分页的 limit 切不可由用户端控制(运营后台可适度放开). 必须由后端控制.

小结

简单总结了分页查询的个人实践.

  1. 采用 start,limit 方式分页
  2. 统一分页查询对象和分页返回对象
  3. 后端控制 limit 大小