基于偏移量、游标分页的详解

前言

大量的数据集往往会被分成多个空间去存储。例如一本书就会有几十页几百页,因为把一本书都放在一页去展示不管是对生产者还是消费者都是及其不友好的。又比如在网页中我们常常会看到一页一页的数据,当然我们自己开发的时候也少不了做分页展示的需求。

基于偏移量进行分页

对于分页我们相较于使用游标进行分页更熟悉、见得更多的是基于偏移量进行分页。 例如这样一个Get请求:brownjay.com/api/v1/books?page=2&size=10

这一个请求会提供一个一页的size和页数,那么我们很容易就可以知道offset为(page-1)*size

后端就会执行select *** from *** limite 10 offset 10

这种分页方式十分简单,只需跳过前面Offset指定的结果数,按需返回Limit个结果数就可以了,它很容易与数据库查询语句对应。

你有100本书,每一页展示10本,那么基于偏移量的分页方式如下。

  • 第一页:Offset:0, Limit:10
  • 第二页:Offset:10, Limit:10
  • 第三页:Offset:20, Limit:10

基于游标进行分页

基于游标分页是怎样的,我通过一个sql便知select *** from ***where id >10 limite 10

不同于使用offset进行偏移的分页,游标是通过cursor去直接进行where进行范围的筛查。 其效果都能拿到那一段区域的数据集

简单实现Demo:

我们定义一个代码分页信息的结构体。

go 复制代码
type Page struct {
	NextID        string `json:"next_id"`
	NextTimeAtUTC int64  `json:"next_time_at_utc"`
	PageSize      int64  `json:"page_size"`
}

其中:

  • NextID就是cursor
  • NextTimeAtUTC记录分页发生的时间点
  • PageSize表示每一页的元素个数

它有一个Encode方法,生成一个使用Base-64编码的令牌。

go 复制代码
// Encode 返回分页token
func (p Page) Encode() Token {
	b, err := json.Marshal(p)
	if err != nil {
		return Token("")
	}
	return Token(base64.StdEncoding.EncodeToString(b))
}

Token代表的是分页令牌,本质上是一个字符串。

go 复制代码
type Token string

它有一个Decode方法,用来从字符串令牌中解析得到分页信息。

go 复制代码
// Decode 解析分页信息
func (t Token) Decode() Page {
	var result Page
	if len(t) == 0 {
		return result
	}

	bytes, err := base64.StdEncoding.DecodeString(string(t))
	if err != nil {
		return result
	}

	err = json.Unmarshal(bytes, &result)
	if err != nil {
		return result
	}

	return result
}

这样一个简单的基于游标的分页功能就实现好了。

最终客户端会在url中携带相应token,我们就会解析出相应的nextID(cursor),而我们在vo中也会返回下一页所对应的token以便客户端进行访问

值得注意的是我们没有直接在API请求链接中使用真实数据的主键等信息,而是使用JSON序列化并使用Base-64编码的字符串来作为token来使用,这样做能防止用户直接解密我们的系统而避免风险

而为什么要在分页信息中记录时间,是为了防止token泄漏后被无限期使用 (爬虫)。我们可以限制token在一个合理时间后失效,也是安全性的一个保障。

优劣势分析

对于偏移量分页

优势:

  • 使用偏移量进行分页实现起来显然是相对更简单,并且这种实现还可以进行跳页进行查询访问

劣势:

  • 1.基于偏移量的分页在数据量很大的场景下,查询效率会比较低。通常 OFFSET 越高,查询时间就越长,而反观where进行筛选则可以使用b+树索引去进行筛选,O(logn)>>O(n)

  • 2.在并发场景下会出现元素重复(offset在第二页时有人在第一页新插入一个数据)或被跳过(offset在第二页时有人在第一页删掉了一个数据)。

  • 3.显式的page参数在支持跳页的同时也会被爬虫并发请求。


对于游标分页

优势:

  1. 1.性能好(where ***可以使用索引)
  2. 2.并发安全
  3. 3.不会被无脑批量爬取

劣势:

  • 1.实现相较于偏移量更复杂
  • 2.不支持跳页
  • 3.不适合多检索条件的场景

最后问问看到封面你会想到哪一句诗呢?😀

相关推荐
接着奏乐接着舞。4 小时前
【2026年7月最新】69道RAG面试题
前端·人工智能·后端·aigc·embedding·rag
edwarddamon4 小时前
Spring Cloud Gateway 全链路 traceId 传递方案
后端
神奇小汤圆4 小时前
我们如何在 Elasticsearch 上构建一个持久 agent 记忆层,实现 0.89 召回率和零租户泄漏
后端
我才是银古4 小时前
基于 robotgo 实现 Windows 桌面 RPA 自动化框架:技术全解
go·rpa·robotgo
掘金一周4 小时前
裁员了,公司很爽快,赔偿一分没少 | 沸点周刊 7.8
前端·人工智能·后端
神奇小汤圆4 小时前
MySQL 5.7 频繁被 Systemd 杀死:一次惊心动魄的故障排查之旅
后端
一只专注api接口开发的技术猿4 小时前
电商评论自动化监控与情感数据分析完整落地教程(附可直接运行 Python 代码)
大数据·数据库·python·数据分析·自动化
hh真是个慢性子4 小时前
GaussDB Inside 2.23.01.280 集中式一主一备安装
数据库·database·gaussdb·国产数据库·高斯
沉静的小伙4 小时前
Spring事务
java·数据库·spring
行思理4 小时前
fastadmin 新手部分功能点
后端·php