分页问题 -Offset-based Pagination 和 Cursor-based Pagination
一、Offset-based Pagination
基于偏移的分页是几乎所有现代框架中最常见的即用型解决方案。 可以指定参数 limit,offset 和 page 等来指定所需的一组特定结果。
查询方式
http://abc.dd.com/list?page=n&count=n
缺点
1.随着数据集的增长,性能变慢,因为会查询页码前面的所有数据。比如 select * from msgs limit 100000, 100; 会查询前 100100 条数据。
2.结果集数据条数发生变化,导致查询数据不准确,在某些情况下,还会返回重复的结果。
优点
可以随意选择页码查询,可以跳页码。
应用场景
管理后台
二、Cursor-based Pagination
基于游标的分页是最有效的技术,可提供最准确的结果。 光标是指指向数据集中特定项目的键集。 它充当记录的指针。 调用 API 时,可以将键集与请求一起传递,以获取游标之前或之后的数据。 还可以传递 limit 参数来限制返回结果集。
查询方式
http://twitter.com/followers/ids/barackobama.xml?cursor=-1
优点
1.性能更好,查询速度更快。 比如 select * from msgs where id > cursor_id limit 100;只会查询 100 条数据。
2.可以按大型数据集进行缩放,并且还提供一致的结果。不会因为数据条数变化导致结果集不准确
缺点
只能从头开始查询连续的页;无法提供记录总数,还阻止跳转到特定页面
应用场景
大数据集翻页可以采用这种 cursor 方式。基于 cursor 的分页的最佳用例是创建带有无限滚动的页面。假定数据集变化非常频繁,并且用户可以经常从用户新闻提要,帖子等中拉出数据集。Twitter 和 Facebook 都是使用这种方式。App 端的分页常用这种方式。
Twitter Cursor Based Pagination 事例:
https://api.twitter.com/1.1/search/tweets.json?q=php&since_id=24012619984051000&max_id=250126199840518145&result_type=recent&count=10
Facebook API Cursor Based Pagination 事例:
{
"data":[
{....},
{....}
],
"paging":{
"cursors":{
"after":"MTAxNTExOTQ1MjAwNzI5NDE=",
"before":"NDMyNzQyODI3OTQw"
},
"previous":"https://graph.facebook.com/me/albums?limit=25&before=NDMyNzQyODI3OTQw",
"next":"https://graph.facebook.com/me/albums?limit=25&after=MTAxNTExOTQ1MjAwNzI5NDE="
}
}
注意事项
1.基于 cursor 的分页,一定要排序;cursor 最好是数据库中自增 id,有序,而且全局唯一,这种情况下实现比较简单。在数据库中可以通过大于或者小于查询到下一页或者上一页的数据。
2.如果数据库中没有自增的 id,cursor 可以选用其他的字段,但是该字段一定要是数字类型,这样可以通过大于或者小于查询到下一页或者上一页,比如 ctime 等时间戳。
3.使用 ctime 做 cursor 的问题是:并发较高时,ctime 容易出现重复。
a.解决办法,cursor 使用 ctime 加一个唯一键比如 order_i 段,然后使用 base64+对称加密对 ctime+order_id 生成一个字符串,生成的该字段作为 cursor.
b.查询时,比如每页查询出 20 条,后端解密出 ctime+order_id,根据 ctime 查询出该时间点有多少条数据,假如有 3 条数据,where ctime > ctimeValue and limit 20+3; 一共查询到 23 条数据,然后通过 order_id 找到需要的 20 条数据。
c.根据新的数据生成新的 cursor 并返回。
关注公众号,输入“java-summary”即可获得源码。
完成,收工!
【传播知识,共享价值】,感谢小伙伴们的关注和支持,我是【诸葛小猿】,一个彷徨中奋斗的互联网民工。
版权声明: 本文为 InfoQ 作者【诸葛小猿】的原创文章。
原文链接:【http://xie.infoq.cn/article/eb3c2c6de00e728e9ec3f47ba】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论