前言
大量的数据集往往会被分成多个空间去存储。例如一本书就会有几十页几百页,因为把一本书都放在一页去展示不管是对生产者还是消费者都是及其不友好的。又比如在网页中我们常常会看到一页一页的数据,当然我们自己开发的时候也少不了做分页展示的需求。
基于偏移量进行分页
对于分页我们相较于使用游标进行分页更熟悉、见得更多的是基于偏移量进行分页。 例如这样一个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.性能好(where ***可以使用索引)
- 2.并发安全
- 3.不会被无脑批量爬取
劣势:
- 1.实现相较于偏移量更复杂
- 2.不支持跳页
- 3.不适合多检索条件的场景
最后问问看到封面你会想到哪一句诗呢?😀