API作翻页的两种思路

在开发API的时候,有时候数据太多了,就须要分页读取。sql

基于偏移量的分页(Offset-based)

这种方式就是会提供一个每页笔数(page size)来定义返回条目的最大数,提供一个页数(page number)来表示从哪里开始读取数据。数据库

例如:服务器

SELECT * FROM "CampusResumes" ORDER BY "Name" DESC LIMIT 5 OFFSET 10;

这句话的意思就是从该表中读取数据,按照Name字段降序排序,从第10笔数据后开始读取,一共读取5笔(可能不足5笔)。分布式

这就至关于page size = 5,page number = 3的分页读取。性能

 

Offset-based分页方式实现起来很是的简单,对用户来讲体验也比较好。可是还有有一些劣势的:大数据

  • 对于大规模的数据集,效率不够高。由于数据库须要进行count和skip操做。
  • 若是数据常常发生变化,那么结果不可信。在查询的时候若是插入或删除了数据,那么某条数据可能会出现两次或者翻页的时候越界了。
  • 在分布式系统中实现起来略麻烦。这种状况下,你可能须要扫描不一样的数据碎片,而后才能获得想要的数据。

整体来讲,当容许结果出现偏差的时候,Offset-based分页仍是很好用的。加密

 

基于游标的分页(Cursor-based)

为了解决Offset-based分页的那些问题,能够采用Cursor-based分页。blog

这种方式是这样的:客户端首先发送请求,请求里提供所需数据的数量。而后服务器响应请求,返回这些数量的数据(若是有这么多数据的话),同时还会返回一个游标(Cursor)。在下一次请求中,客户端除了发送请求数据的数量以外,还把这个cursor也传送过去,这个cursor就表示此次所要读取的数据的开始位置。排序

这看起来和Offset-based分页差异不大,可是却更有效率。数据库里面的数据能够根据cursor值来获取。索引

例如:

SELECT * FROM "CampusResumes" WHERE "Id" > 15 ORDER BY "Id" LIMIT 5;

这个例子里,上次请求返回的cursor(Id字段)值为15,此次要获取Id比15大的连续的5条数据。

这里的Id字段自己就是一个索引,因此查询起来很是快。

在此次请求的响应里,能够把本次结果的最后一条的Id做为cursor再返回去:

因此返回的cursor值为23,以供下次读取。

 

Cursor-based翻页的优势是:

  • 性能好。由于cursor字段一般都是索引列,查起来很快。
  • 一致性。添加和删除数据并不影响返回的结果,翻页时同一笔数据也只会被返回一次。

Cursor-based翻页一般适用于大量和动态的数据集,可是它也有一些缺点

  • 没法跳转到指定的页。Cursor-based翻页只能一页一页遍历结果。
  • 结果必须基于一个惟一而且顺序的字段。不可让添加记录到任意位置。
  • 实现起来比Offset-based复杂一点,尤为对客户端来讲。

对于Cursor字段的选择:

  • Id,顺序的主键。
  • 时间戳
  • 加密字符串。它们看起来像随机字符串,但实际上一般是Cursor里加入了额外的信息。

整体来讲Cursor-based翻页仍是更适合于高吞吐的应用,这种状况下客户端一般须要扫描整个数据集。

 

翻页的最佳实践

  • 设定每页的最大笔数限制。
  • 针对大数据集,尽可能不要使用Offset-based分页。
  • 分页的默认排序,一般会把新的数据先返回,旧的数据日后翻。
  • 没分页的API尽可能去实现分页。
  • 分页的时候,最好把下一页的连接一同返回,并鼓励客户端使用这个连接,参考HATEOAS。这样之后你改变翻页策略的时候,客户端不会爆掉。
  • 不要在Cursor里加入敏感信息
相关文章
相关标签/搜索