前提
❝这是一篇Redis命令使用不当的踩坑经历分享
❞
笔者最近在做一个项目时候使用Redis
存放客户端展示的订单列表,列表需要进行分页。由于笔者先前对Redis
的各种数据类型的使用场景并不是十分熟悉,于是先入为主地看到Hash
类型的数据结构,假定:
USER_ID:1
ORDER_ID:ORDER_XX: {"amount": "100","orderId":"ORDER_XX"}
ORDER_ID:ORDER_YY: {"amount": "200","orderId":"ORDER_YY"}
感觉Hash
类型完全满足需求实现的场景。然后想当然地考虑使用HSCAN
命令进行分页,引发了后面遇到的问题。
SCAN和HSCAN命令
SCAN
命令如下:
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
// 返回值如下:
// 1. cursor,数值类型,下一轮的起始游标值,0代表遍历结束
// 2. 遍历的结果集合,列表
SCAN
命令在Redis2.8.0
版本中新增,时间复杂度计算如下:每一轮遍历的时间复杂度为O(1)
,所有元素遍历完毕直到游标cursor
返回0的时间复杂度为O(N)
,其中N
为集合内元素的数量。SCAN
是针对整个Database
内的所有KEY
进行渐进式的遍历,它不会一直阻塞Redis
,也就是使用SCAN
命令遍历KEY
的性能有可能会优于KEY *
命令。对于Hash
类型有一个衍生的命令HSCAN
专门用于遍历Hash
类型及其相关属性(Field
)的字段:
HSCAN key cursor [MATCH pattern] [COUNT count]
// 返回值如下:
// 1. cursor,数值类型,下一轮的起始游标值,0代表遍历结束
// 2. 遍历的结果集合,是一个映射
笔者当时没有仔细查阅Redis
的官方文档,想当然地认为Hash
类型的分页简单如下(偏激一点假设每页数据只有1条):
// 第一页
HSCAN USER_ID:1 0 COUNT 1