通过使用游标而不是偏移量进行API分页设计

2020-12-27 09:27:27

返回给定查询的所有结果对于API可能是一个挑战,尤其是在有成千上万个结果的情况下。它给服务器,客户端,网络带来了负担,通常是不必要的。人们因此发明了分页。

分页的常用方法是偏移量或页码。所以您发出这样的请求:

如果是简单的偏移量,它看起来像是?offset = 1000和?offset = 1100-是相同的旧汤,只是重新加热了。它可以直接进入SQL查询(例如OFFSET 1000 LIMIT 100),也可以乘以页面大小(即LIMIT值)。无论如何,这都是次优的解决方案,因为每个数据库都必须跳过那1000行。要跳过它们,需要识别它们。不管是PostgreSQL,ElasticSearch还是MongoDB,都必须对其进行排序,计数并丢弃。

这是一种没人需要的工作。但是,由于易于实现,它会一遍又一遍地重复-您可以直接将API映射到查询的数据库中。

那你怎么办呢?我们可以看看数据库能做什么!他们有一个称为游标的概念,它是指向行的指针。因此,您可以对数据库说“在那之后还给我100行”。数据库的操作要容易得多,因为您很有可能会通过带有索引的字段来识别行。突然之间,您不需要获取和跳过这些行,就可以直接越过它们。

API返回一个(不透明的)字符串,您可以使用它来检索下一页:

在实现方面有很多选择。通常,您有一些订购条件,例如产品ID。在这种情况下,您将使用某种可逆算法(例如,哈希码)对产品ID进行编码。并在收到带有游标的请求后,将其解码并生成一个查询,例如WHERE id> :光标限制为100。

=#说明分析产品偏移量10000限制100中的选择ID;查询计划------------------------------------------------ -------------------------------------------------- -------------------------------限制(费用= 1114.26..1125.40行= 100宽度= 4)(实际时间= 39.431..39.561行= 100循环= 1)->对产品进行Seq扫描(成本= 0.00..1274406.22行= 11437243宽度= 4)(实际时间= 0.015..39.123行= 10100循环= 1)计划时间:0.117毫秒执行时间:39.589毫秒

=#解释分析ID为>的产品中的选择ID。 10000限制100;查询计划------------------------------------------------ -------------------------------------------------- ----------------------------限制(费用= 0.00..11.40行= 100宽度= 4)(实际时间= 0.016 .. 0.067行= 100循环= 1)->对产品进行序列扫描(成本= 0.00..1302999.32行= 11429082宽度= 4)(实际时间= 0.015..0.052行= 100循环= 1)过滤器:(id> 10000)计划时间:0.164 ms执行时间:0.094多发性硬化症

这相差几个数量级!当然,实际数字取决于表的大小,过滤器和商店实现。有一篇很棒的文章提供了更多的技术信息-内嵌了幻灯片,有关性能比较,请参见幻灯片42。

当然,没有人按ID订购产品-您通常按相关性订购产品(然后按ID作为平局决定)。在现实世界中,您必须查看数据才能确定要做什么。订单可以按ID排序(单调递增)。愿望清单项目也可以像这样订购-通过愿望清单时间。在我们的案例中,产品来自ElasticSearch,它自然支持此游标。

您会看到一个不足之处,就是无法使用无状态API生成“上一页”链接。因此,在面向用户的分页的情况下,如果要具有上一个/下一个和“直接进入第10页”按钮很重要,则无法解决此偏移/限制问题。但是在其他情况下,使用基于游标的分页可以大大提高性能,尤其是在具有深分页的非常大的表上。