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

前言

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

基于偏移量进行分页

对于分页我们相较于使用游标进行分页更熟悉、见得更多的是基于偏移量进行分页。 例如这样一个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.不适合多检索条件的场景

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

相关推荐
岁岁种桃花儿6 小时前
MySQL从入门到精通系列:InnoDB记录存储结构
数据库·mysql
jiunian_cn7 小时前
【Redis】hash数据类型相关指令
数据库·redis·哈希算法
冉冰学姐7 小时前
SSM在线影评网站平台82ap4(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm框架·在线影评平台·影片分类
知识分享小能手8 小时前
SQL Server 2019入门学习教程,从入门到精通,SQL Server 2019数据库的操作(2)
数据库·学习·sqlserver
踩坑小念9 小时前
秒杀场景下如何处理redis扣除状态不一致问题
数据库·redis·分布式·缓存·秒杀
索荣荣10 小时前
Java Session 全面指南:原理、应用与实践(含 Spring Boot 实战)
java·spring boot·后端
萧曵 丶10 小时前
MySQL 语句书写顺序与执行顺序对比速记表
数据库·mysql
Wiktok11 小时前
MySQL的常用数据类型
数据库·mysql
千寻技术帮11 小时前
10333_基于SpringBoot的家电进存销系统
java·spring boot·后端·源码·项目·家电进存销
dear_bi_MyOnly11 小时前
【多线程——线程状态与安全】
java·开发语言·数据结构·后端·中间件·java-ee·intellij-idea