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

前言

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

基于偏移量进行分页

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

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

相关推荐
三水不滴5 分钟前
Elasticsearch 实战系列(二):SpringBoot 集成 Elasticsearch,从 0 到 1 实现商品搜索系统
经验分享·spring boot·笔记·后端·elasticsearch·搜索引擎
奇点爆破XC9 分钟前
统计数据库当前数据容量
数据库
Leon-Ning Liu12 分钟前
OGG同步Oracle到Kafka
数据库·oracle·kafka
远方160916 分钟前
117-Oracle 26ai FILTER(过滤)子句新特性
大数据·数据库·sql·oracle·database
Maverick0616 分钟前
Oracle 归档日志(Archive Log)操作手册
数据库·oracle
Amour恋空17 分钟前
Nacos服务发现与配置
java·后端·服务发现
isNotNullX17 分钟前
一文讲清8大数据清洗方法
大数据·数据库·数据挖掘·数据迁移
uzong22 分钟前
为什么是你来做?面试中犀利问题的底层逻辑是什么和标准回答模版
后端·面试
比特森林探险记27 分钟前
Go 语言依赖注入和java 区别
go
Francek Chen29 分钟前
【大数据存储与管理】分布式数据库HBase:05 HBase运行机制
大数据·数据库·hadoop·分布式·hdfs·hbase