SCAN及相关SSCAN,HSCAN和ZSCAN命令解析

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云解析 DNS,旗舰版 1个月
简介: SCAN及相关SSCAN,HSCAN和ZSCAN命令解析


一、概述


语法:


SCAN cursor [MATCH pattern] [COUNT count]


  • cursor - 游标。
  • pattern - 匹配的模式。
  • count - 指定从数据集里返回多少元素,默认值为 10 。


起始版本:2.8.0


时间复杂度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.


(中文,考虑到有些靓仔英文看不懂!我反正看不懂)O(1)表示每个调用。O(N)表示一个完整的迭代,包括足够的命令调用,使光标返回到0。N是集合内的元素数。


  • SCAN 命令用于迭代当前数据库中的key集合。
  • SSCAN 命令用于迭代SET集合中的元素。
  • HSCAN 命令用于迭代Hash类型中的键值对。
  • ZSCAN 命令用于迭代SortSet集合中的元素和元素对应的分值


以上列出的四个命令都支持增量式迭代,它们每次执行都只会返回少量元素,所以这些命令可以用于生产环境,而不会出现像 EYS 或者 SMEMBERS 命令带来的可能会阻塞服务器的问题。


不过,SMEMBERS 命令可以返回集合键当前包含的所有元素, 但是对于SCAN这类增量式迭代命令来说,有可能在增量迭代过程中,集合元素被修改,对返回值无法提供完全准确的保证。


因为 SCAN, SSCAN, HSCAN 和 ZSCAN 四个命令的工作方式都非常相似, 所以这个文档会一并介绍这四个命令,需要注意的是SSCAN, HSCAN ,ZSCAN命令的第一个参数总是一个key; SCAN 命令则不需要在第一个参数提供任何key,因为它迭代的是当前数据库中的所有key。


说明:SSCAN,HSCAN,ZSCAN是针对于SET,HASH,SortSet类型的一个scan扩展,用法和scan一样


所以掌握的SCAN和用法,那么它下面的扩展命令还不是收到擒来


image.png


二、SCAN命令基本用法


SCAN命令是一个基于游标的迭代器。这意味着命令每次被调用都需要使用上一次这个调用返回的游标作为该次调用的游标参数,以此来延续之前的迭代过程当SCAN命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束


案例:


127.0.0.1:6379> flushall
OK
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 k4 v4 k5 v5 k6 v6 k7 v7 k8 v8 k9 v9 k10 v10 k11 v11  #添加key和值
OK
127.0.0.1:6379> mset k12 v12 k13 v13 k14 v14 k15 v15 k16 v16 k17 v17 k18 v18 k19 v19 k20 v20
OK
127.0.0.1:6379> scan 0    #开始第一次遍历,游标为 0 表示开始新的遍历
1) "14"
2)  1) "k8"
    2) "k11"
    3) "k2"
    4) "k19"
    5) "k14"
    6) "k13"
    7) "k4"
    8) "k10"  
    9) "k15"
   10) "k1"
127.0.0.1:6379> scan 14   #继续接着上一次遍历,游标设置上一次返回数组的第一个元素值 14 
1) "15"
2)  1) "k6"
    2) "k5"
    3) "k16"
    4) "k3"
    5) "k12"
    6) "k7"
    7) "k18"
    8) "k9"
    9) "k20"
   10) "k17"
127.0.0.1:6379> scan 15   #当返回数组的第一个元素值时0的时候表示集合遍历完毕
1) "0"
2) (empty list or set)
127.0.0.1:6379> 


在上面这个例子中, 第一次迭代使用 0 作为游标, 表示开始一次新的迭代。第二次迭代使用的是第一次迭代时返回的游标 14 ,作为新的迭代参数 。显而易见,SCAN命令的返回值 是一个包含两个元素的数组在第三次调用 SCAN 命令时, 命令返回了游标 0 , 这表示迭代已经结束, 整个数据集已经被完整遍历过了。


full iteration :以 0 作为游标开始一次新的迭代, 一直调用 SCAN 命令, 直到命令返回游标 0 , 我们称这个过程为一次完整遍历。


2.1 SCAN命令的保证

SCAN命令以及其他增量式迭代命令, 在进行完整遍历的情况下可以为用户带来以下保证:


  • 会遍历到集合中的每一个元素(在遍历期间):从完整遍历开始直到完整遍历结束期间, 一直存在于数据集内的所有元素都会被完整遍历返回; 这意味着, 如果有一个元素, 它从遍历开始直到遍历结束期间都存在于被遍历的数据集当中, 那么 SCAN 命令总会在某次迭代中将这个元素返回给用户。


  • 不存在集合中的元素不会遍历出来(在遍历期间):同样,如果一个元素在开始遍历之前被移出集合,并且在遍历开始直到遍历结束期间都没有再加入,那么在遍历返回的元素集中就不会出现该元素。


然而因为增量式命令仅仅使用游标来记录迭代状态, 所以这些命令带有以下缺点:


  • 从集合中遍历出的元素可能会重复:同一个元素可能会被返回多次。 处理重复元素的工作交由应用程序负责, 比如说, 可以考虑将迭代返回的元素仅仅用于可以安全地重复执行多次的操作上。


  • 遍历期间添加或删除集合数据时,在这些数据也可能会被返回:如果一个元素是在迭代过程中被添加到数据集的, 又或者是在迭代过程中从数据集中被删除的, 那么这个元素可能会被返回, 也可能不会。


image.png


2.2 SCAN命令每次执行返回的元素数量

SCAN增量式迭代命令并不保证每次执行都返回某个给定数量的元素,甚至可能会返回零个元素, 但只要命令返回的游标不是 0 , 应用程序就不应该将迭代视作结束。


不过命令返回的元素数量总是符合一定规则的, 对于一个大数据集来说, 增量式迭代命令每次最多可能会返回数十个元素;而对于一个足够小的数据集来说, 如果这个数据集的底层表示为编码数据结构(小的sets, hashes and sorted sets), 那么增量迭代命令将在一次调用中返回数据集中的所有元素。


如果需要的话,用户可以通过增量式迭代命令提供的COUNT选项来指定每次迭代返回元素的最大值。


2.3 COUNT选项

对于增量式迭代命令不保证每次迭代所返回的元素数量,我们可以使用COUNT选项, 对命令的行为进行一定程度上的调整。COUNT 选项的作用就是让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素。使用COUNT 选项对于对增量式迭代命令相当于一种提示, 大多数情况下这种提示都比较有效的控制了返回值的数量。


  • COUNT 参数的默认值为 10 。
  • 数据集比较大时,如果没有使用MATCH 选项, 那么命令返回的元素数量通常和 COUNT 选项指定的一样, 或者比 COUNT 选项指定的数量稍多一些。
  • 在迭代一个编码为整数集合(intset,一个只由整数值构成的小集合)、 或者编码为压缩列表(ziplist,由不同值构成的一个小哈希或者一个小有序集合)时, 增量式迭代命令通常会无视 COUNT 选项指定的值, 在第一次迭代就将数据集包含的所有元素都返回给用户。


注意: 并非每次迭代都要使用相同的 COUNT 值,用户可以在每次迭代中按自己的需要随意改变 COUNT 值, 只要记得将上次迭代返回的游标用到下次迭代里面就可以了。


2.4 MATCH 选项

类似于KEYS 命令,增量式迭代命令通过给定 MATCH 参数的方式实现了通过提供一个 glob 风格的模式参数, 让命令只返回和给定模式相匹配的元素。

以下是一个使用 MATCH选项进行迭代的示例:


127.0.0.1:6379> mset m1 n1 m2 n2 m3 n3
OK
127.0.0.1:6379> keys *    #查看所有key
 1) "k8"
 2) "k5"
 3) "k14"
 4) "k18"
 5) "k10"
 6) "k15"
 7) "m1"
 8) "k4"
 9) "m2"
10) "k11"
11) "k16"
12) "k13"
13) "k9"
14) "k19"
15) "k3"
16) "k12"
17) "m3"
18) "k1"
19) "k20"
20) "k17"
21) "k2"
22) "k7"
23) "k6"
127.0.0.1:6379> scan 0 match m*   #按照特定规则的方式遍历
1) "22"
2) 1) "m1"
127.0.0.1:6379> scan 22 match m*
1) "19"
2) 1) "m3"
   2) "m2"
127.0.0.1:6379> scan 19 match m*
1) "0"
2) (empty list or set)
127.0.0.1:6379> 


MATCH功能对元素的模式匹配工作是在命令从数据集中取出元素后和向客户端返回元素前的这段时间内进行的, 所以如果被迭代的数据集中只有少量元素和模式相匹配, 那么迭代命令或许会在多次执行中都不返回任何元素。


redis 127.0.0.1:6379> scan 0 MATCH *11*
1) "288"
2) 1) "key:911"
redis 127.0.0.1:6379> scan 288 MATCH *11*
1) "224"
2) (empty list or set)
redis 127.0.0.1:6379> scan 224 MATCH *11*
1) "80"
2) (empty list or set)
redis 127.0.0.1:6379> scan 80 MATCH *11*
1) "176"
2) (empty list or set)
redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000
1) "0"
2)  1) "key:611"
    2) "key:711"
    3) "key:118"
    4) "key:117"
    5) "key:311"
    6) "key:112"
    7) "key:111"
    8) "key:110"
    9) "key:113"
   10) "key:211"
   11) "key:411"
   12) "key:115"
   13) "key:116"
   14) "key:114"
   15) "key:119"
   16) "key:811"
   17) "key:511"
   18) "key:11"
redis 127.0.0.1:6379>


可以看出,以上的大部分迭代都不返回任何元素。在最后一次迭代, 我们通过将 COUNT 选项的参数设置为 1000 , 强制命令为本次迭代扫描更多元素, 从而使得命令返回的元素也变多了。


2.5 并发执行多个迭代

在同一时间, 可以有任意多个客户端对同一数据集进行迭代, 客户端每次执行迭代都需要传入一个游标, 并在迭代执行之后获得一个新的游标, 而这个游标就包含了迭代的所有状态, 因此, 服务器无须为迭代记录任何状态。


2.6 中止迭代

因为迭代的所有状态都保存在游标里面, 而服务器无须为迭代保存任何状态, 所以客户端可以在中途停止一个迭代, 而无须对服务器进行任何通知。即使有任意数量的迭代在中途停止, 也不会产生任何问题。


image.png


2.7 使用错误的游标

使用SCAN 命令传入间断的(broken)、负数、超出范围或者其他非正常的游标来执行增量式迭代并不会造成服务器崩溃, 但可能会让命令产生未定义的行为。未定义行为指的是, 增量式命令对返回值所做的保证可能会不再为真。 只有两种游标是合法的:


在开始一个新的迭代时, 游标必须为 0 。

增量式迭代命令在执行之后返回的, 用于延续迭代过程的游标。


2.8 迭代能终止的前提

增量式迭代命令所使用的算法只保证在数据集的大小有界的情况下, 迭代才会停止, 换句话说, 如果被迭代数据集的大小不断地增长的话, 增量式迭代命令可能永远也无法完成一次完整迭代。


从直觉上可以看出, 当一个数据集不断地变大时, 想要访问这个数据集中的所有元素就需要做越来越多的工作, 能否结束一个迭代取决于用户执行迭代的速度是否比数据集增长的速度更快。


2.9 返回值

SCAN, SSCAN, HSCAN 和 ZSCAN 命令都返回一个包含两个元素的 multi-bulk 回复: 回复的第一个元素是字符串表示的无符号 64 位整数(游标), 回复的第二个元素是另一个 multi-bulk 回复, 包含了本次被迭代的元素。


SCAN 命令返回的每个元素都是一个key。

SSCAN 命令返回的每个元素都是一个集合成员。

HSCAN 命令返回的每个元素都是一个键值对,一个键值对由一个键和一个值组成。

ZSCAN命令返回的每个元素都是一个有序集合元素,一个有序集合元素由一个成员(member)和一个分值(score)组成。


2.10 另外的例子

迭代hash中的键值对:


127.0.0.1:6379> hmset vipclient name j3_liuliang age 18 #添加hash类型数据
OK
127.0.0.1:6379> hscan vipclient 0 #开始迭代
1) "0"
2) 1) "name"
   2) "j3_liuliang"
   3) "age"
   4) "18"
127.0.0.1:6379> 


结束语


  • 本文结合Redis中文网和博主的实践案例及理解所写,算是一种扩展把对Redis的命令
  • 由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。
  • 如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。
  • 感谢您的阅读,十分欢迎并感谢您的关注。


image.png

目录
相关文章
|
1月前
|
网络协议 开发工具 C语言
Jetson错误(二):wget命令提示无法解析主机地址的问题解决
对于解决在NVIDIA Jetson平台上使用wget命令时出现的无法解析主机地址的问题,提供了两种解决方法:一种是临时修改DNS服务器为Google的公共DNS,另一种是永久修改DNS设置。
91 5
|
2月前
|
存储 缓存 NoSQL
Redis 过期删除策略与内存淘汰策略的区别及常用命令解析
Redis 过期删除策略与内存淘汰策略的区别及常用命令解析
71 0
|
3月前
|
图形学 开发者 存储
超越基础教程:深度拆解Unity地形编辑器的每一个隐藏角落,让你的游戏世界既浩瀚无垠又细节满满——从新手到高手的全面技巧升级秘籍
【8月更文挑战第31天】Unity地形编辑器是游戏开发中的重要工具,可快速创建复杂多变的游戏环境。本文通过比较不同地形编辑技术,详细介绍如何利用其功能构建广阔且精细的游戏世界,并提供具体示例代码,展示从基础地形绘制到植被与纹理添加的全过程。通过学习这些技巧,开发者能显著提升游戏画面质量和玩家体验。
151 3
|
3月前
|
数据采集 运维 监控
运维笔记:流编辑器sed命令用法解析
运维笔记:流编辑器sed命令用法解析
57 5
|
3月前
|
Linux 数据安全/隐私保护 Perl
解锁Linux高手秘籍:文件操作+命令解析大揭秘,面试场上让你光芒万丈,技术实力惊艳四座!
【8月更文挑战第5天】Linux作为服务器与嵌入式系统的基石,其文件管理和命令行操作是技术人员必备技能。本文从文件操作和基础命令两大方面,深入浅出地解析Linux核心要义,助你在面试中脱颖而出。首先探索文件系统的树状结构及操作,包括使用`ls -la`浏览文件详情、`touch`创建文件、`rm -r`慎删目录、`cp`与`mv`复制移动文件、以及利用`find`搜索文件。接着掌握命令行技巧,如用`cat`、`more`和`less`查看文件内容;借助`grep`、`sed`与`awk`处理文本;运用`ps`、`top`和`kill`管理进程;并通过`chmod`和`chown`管理文件权限。
79 8
|
3月前
|
运维 Ubuntu Shell
Docker命令宝典:解锁容器化技术的无限可能,从镜像管理到容器操作,全面解析与实战指南!
【8月更文挑战第3天】Docker简化了应用的部署与运行,掌握其基本命令对开发者和运维人员至关重要。通过`docker images`可查看本地镜像;使用`docker pull`拉取如最新版Ubuntu镜像;`docker rmi`用于删除不再需要的镜像。运行容器可通过`docker run`命令,结合`-it`等选项提供交互式环境。`docker ps`显示运行中的容器,加上`-a`则列出所有容器。`docker stop`和`docker start`分别用于停止和重启容器,而`docker rm`则删除容器。
83 5
|
4月前
|
Linux Docker 容器
ip addr命令解析
ip addr命令解析
535 1
|
3月前
|
运维 Rust 监控
Linux高效运维必备:fd命令深度解析,文件描述符管理从此得心应手!
【8月更文挑战第23天】本文介绍了一款名为fd的命令行工具,该工具基于Rust语言开发,旨在以更直观的语法和更快的速度替代传统的`find`命令。通过本文,您可以了解到如何安装fd以及一些基本用法示例,比如使用正则表达式匹配文件名、排除特定目录等。此外,文章还展示了如何结合`ps`和`lsof`命令来查找特定文件并显示其文件描述符,从而帮助您更好地管理和监控Linux系统中的文件与进程。
131 0
|
4月前
|
Linux
《解析 Linux 命令:systemd-delta》
`systemd-delta`: 解析Linux服务配置差异。概览: 显示服务单元文件与默认配置的对比,助于配置问题排查与系统审计。特点: 清晰展示修改点,涵盖启动选项等。示例: `systemd-delta [--plain] <service>`. 注意: 理解默认配置,谨慎修改,定期检查。掌握此命令,深化系统服务配置洞察,优化Linux管理。#Linux #systemd-delta
|
4月前
|
存储 监控 Linux
stdbuf命令在Linux中的深度解析
`stdbuf`是Linux工具,用于控制命令的stdin、stdout和stderr的缓冲模式。它可以设置为无缓冲、行缓冲或块缓冲,以优化数据处理和实时性。例如,`stdbuf -o0 cmd`禁用cmd的输出缓冲,`-oL`则按行缓冲。在需要实时监控或高效处理大量数据时,选择合适的缓冲模式至关重要。注意,过度使用无缓冲可能影响性能,并非所有系统都支持`stdbuf`。

推荐镜像

更多