前言
最近在研究知乎和掘金API时,发现他们的下滑加载用的并不是我们传统的页码分页,即page-size或者/offset-limit分页方式,而是一种参数为cursor-limit的分页方式,这是什么来的?它和我们常用的页码分页有什么区别?有什么优缺点?带着这些问题开始学习~
掘金API分页方式
首先以掘金的最新文章APi为例,每当我加载更多文章时,cursor值就会发生微小的改变,观察一下就能看出cursor的值是经过base64编码过的。
1 | curl --location '<https://api.juejin.cn/recommend_api/v1/article/recommend_all_feed>' \\ |
让我们解码一下,就可以看到一个json字符串,这里的v值便是某次请求时第一篇文章的id主键,i便是我们平常数据库中的offset。
1 | {"v":"7317252368546758696","i":20} |
我们每次请求后,响应体里总会返回一个的游标值,作为下一次加载更多文章的时的参数,随着每次滚动,i值就会不断累加,同时当i值过大时,v值的id也会发生改变,变为上次请求的第一篇文章的id,i值重新变为20。
1 | ... |
基于游标分页方式
Google了一下就知道掘金API这种分页方式被称为游标分页(Cursor-based Pagination),它并不是像传统基于页码方式,而是基于记录本身的一个唯一标识(游标),来获取下一批数据。
我们先来回忆一下基于页码分页的缺点
以MySQL为例,当分页过深、即offset的值过大时,读取数据也就越耗时,因为数据库需要读取前面的行并跳过。
同时在并发场景下会出现读取的数据重复,例如当读取第二页时,第一页的数据新增或者删除,都u有可能影响到第二页的数据读取。
那么基于游标方式分页呢?
我们通过指定ID的方式,就可以告诉数据库从哪里开始直接读取,就可以避免多余的跳过操作,提高数据库的读取效率,同时因为指定了ID能够减少因数据变动导致的数据重复或遗漏问题。
但缺点也很明显,就是不能跳页了,用户并不能直接跳到数据列表中的任意位置。
那么什么时候用页码和游标的分页方式呢?
我觉得还是要看具体的业务场景,还是以知乎和掘金API为例,可以看到他们本身业务场景就没有总页数和分页跳转的说法,加载数据都是不断下滑来实现的,因此游标分页方式来加载数据就很适合了。
游标分页方式有很多具体的实现,知乎的游标分页就直接将下一页的HTTP地址直接返回,或者简单一点直接返回对应主键的ID等。最终用SQL来表示都是如下格式
1 | SELECT id, data FROM items WHERE id > ? ORDER BY id ASC LIMIT ? |
小结
- 页码分页适合数据量较小,记录变动不频繁的场景,用户可以方便地跳转到数据集的任意位置
- 游标分页适用于大型、动态变化的数据集,尤其是在数据实时更新和用户需要顺序遍历数据时
当然啦,使用什么技术方案还是要看具体的业务场景,在实际业务中有很多数据量很大,还是使用页码分页的情况,这就需要其他方式来优化了~