非常教程

Redis参考手册

键 | Keys

scan

SCAN cursor [MATCH pattern] [COUNT count]

自2.8.0起可用。

时间复杂度: O(1)用于每个呼叫。O(N)进行完整的迭代,包括足够的命令调用以使游标返回0. N是集合中元素的数量。

使用 SCAN 命令和密切相关的命令 SSCAN,HSCAN 和 ZSCAN 来递增地遍历一组元素。

  • SCAN 迭代当前选定的 Redis 数据库中的一组键。
  • SSCAN 迭代 Sets 类型的元素。
  • HSCAN 迭代哈希类型的字段及其关联值。
  • ZSCAN 迭代 Sorted Set 类型的元素及其相关分数。

由于这些命令允许增量迭代,每次调用只返回少量元素,因此可以在生产中使用它们,而无需像 KEYS 或 SMEMBERS 这样的命令可能会在被调用时长时间(甚至几秒)阻塞服务器的缺点键或元素的大集合。

然而,尽管像 SMEMBERS 这样的阻塞命令能够在给定时刻提供集合中的所有元素,但 SCAN 系列命令仅对返回的元素提供有限的保证,因为我们递增迭代的集合可能在迭代过程中发生更改。

请注意,SCAN,SSCAN,HSCAN 和 ZSCAN 的工作方式非常相似,因此本文档涵盖了所有四个命令。然而,一个明显的区别是,对于SSCAN,HSCAN 和 ZSCAN,第一个参数是保存 Set,Hash 或 Sorted Set 值的密钥的名称。SCAN 命令不需要任何键名参数,因为它在当前数据库中迭代键,所以迭代对象就是数据库本身。

SCAN的基本用法

SCAN 是一个基于游标的迭代器。这意味着在每次调用该命令时,服务器都会返回一个更新的游标,用户需要在下一次调用中将其用作游标参数。

当光标设置为0时开始迭代,当服务器返回的光标为0时终止迭代。以下是 SCAN 迭代的示例:

redis 127.0.0.1:6379> scan 0
1) "17"
2)  1) "key:12"
    2) "key:8"
    3) "key:4"
    4) "key:14"
    5) "key:16"
    6) "key:17"
    7) "key:15"
    8) "key:10"
    9) "key:3"
   10) "key:7"
   11) "key:1"
redis 127.0.0.1:6379> scan 17
1) "0"
2) 1) "key:5"
   2) "key:18"
   3) "key:0"
   4) "key:2"
   5) "key:19"
   6) "key:13"
   7) "key:6"
   8) "key:9"
   9) "key:11"

在上面的例子中,第一个调用使用零作为游标,以开始迭代。第二次调用使用前一次调用返回的游标作为回复的第一个元素,即17。

正如你所看到的,SCAN返回值 是一个包含两个值的数组:第一个值是下一次调用中使用的新游标,第二个值是元素数组。

由于在第二次调用中返回的游标是0,所以服务器向调用者发信号通知完成迭代,并且集合被完全探索。使用游标值0开始迭代,并调用 SCAN,直到返回的游标再次为0,称为完整迭代

扫描保证

SCAN 命令和 SCAN 系列中的其他命令能够向用户提供与完整迭代关联的一组保证。

  • 完整迭代总是从完整迭代的开始到结束检索集合中存在的所有元素。这意味着如果迭代开始时给定元素位于集合内部,并且在迭代终止时仍然存在,那么在某个点 SCAN 将其返回给用户。
  • 完整迭代从不会返回集合中不存在的任何元素,从完整迭代的开始到结束。因此,如果一个元素在迭代开始之前被移除,并且在迭代过程中永远不会将其添加回集合中,SCAN可以确保这个元素永远不会被返回。

但是由于 SCAN 只有很少的状态相关(只是光标),它有以下缺点:

  • 给定的元素可能会多次返回。应用程序可以处理重复元素的情况,例如仅使用返回的元素来执行多次重新应用时安全的操作。
  • 在整个迭代过程中并不总是出现在集合中的元素可能被返回或不被返回:它是未定义的。

每次 SCAN 呼叫返回的元素数量

SCAN 家族功能不保证每次通话返回的元素数量都在给定的范围内。这些命令还允许返回零个元素,并且只要返回的游标不为零,客户端就不应该考虑迭代完成。

然而,返回的元素的数量是合理的,也就是说,实际上,SCAN 可能会在迭代大集合时返回数十个元素的最大数量的元素,或者可能会将集合中的所有元素一次返回当迭代集合足够小以便在内部表示为编码数据结构(这发生在小集合,散列和有序集合)时调用。

但是,用户可以使用 COUNT 选项调整每次呼叫返回元素数量级的顺序。

COUNT选项

虽然 SCAN 不提供有关每次迭代返回的元素数量的保证,但可以使用 COUNT 选项凭经验调整 SCAN 的行为。基本上用 COUNT,用户指定了每次调用应该完成的工作量,以便从集合中检索元素。这只是实现的一个暗示,但是一般来说,这是您实施过程中大部分时间所期望的。

  • COUNT 的默认值是10。
  • 当迭代密钥空间,或者一个足够大的集合,哈希或排序集合,以便用哈希表表示时(假设没有使用 MATCH 选项),服务器通常会返回计数或比每次调用的计数元素多一点。
  • 迭代编码为 intsets 的集合(由整数组成的小集合)或编码为 ziplists 的哈希和排序集(小哈希和由小个别值组成的集合)时,通常所有元素都在第一个 SCAN 调用中返回,而不管 COUNT 值。

重要提示:每次迭代都不需要使用相同的 COUNT 值。调用者可以根据需要自由地将计数从一次迭代更改为另一次迭代,只要在下次调用中传递的游标是在先前对该命令的调用中获得的游标。

MATCH选项

只能迭代匹配给定全局样式模式的元素,类似于只将模式作为参数的 KEYS 命令的行为。

为此,只需MATCH <pattern>在 SCAN 命令末尾附加参数(它可与所有 SCAN 系列命令一起使用)。

这是一个使用 MATCH 进行迭代的例子:

redis 127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood
(integer) 6
redis 127.0.0.1:6379> sscan myset 0 match f*
1) "0"
2) 1) "foo"
   2) "feelsgood"
   3) "foobar"
redis 127.0.0.1:6379>

重要的是要注意,在将数据返回给客户端之前,在从集合中检索元素之后应用 MATCH 过滤器。这意味着如果模式匹配集合中很少的元素,SCAN 很可能在大多数迭代中都不返回元素。一个例子如下所示:

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,以强制命令为该迭代执行更多扫描。

多重并行迭代

无限数量的客户端可能会同时迭代同一个集合,因为迭代器的完整状态在游标中,每次调用都会获取并返回给客户端。服务器端根本没有状态。

终止中间的迭代

由于没有状态服务器端,但全状态由光标捕获,因此调用者可以自由地在半途中终止一次迭代,而无需以任何方式将此信号通知给服务器。无限次的迭代可以开始,并且不会在没有任何问题的情况下终止。

使用损坏的光标调用SCAN

调用带有破损,负值,超范围或其他无效光标的 SCAN 将导致未定义的行为,但不会导致崩溃。未定义的是,对于返回元素的保证不能再由 SCAN 实现来保证。

唯一有效的游标是:

  • 开始迭代时光标值为0。
  • 前一次调用 SCAN 返回的光标为了继续迭代。

保证终止

SCAN 算法只有在迭代集合的大小保持限定为给定的最大大小时才被保证终止,否则迭代总是增长的集合可能导致 SCAN 永远不会终止完整迭代。

这很容易直观地看到:如果集合增长,为了访问所有可能的元素需要做更多的工作,并且终止迭代的能力取决于 SCAN 调用的次数和它的 COUNT 选项值,与收藏增长的速度。

返回值

SCAN,SSCAN,HSCAN 和 ZSCAN 返回一个双元素多批量回复,其中第一个元素是一个表示无符号64位数字(游标)的字符串,第二个元素是具有元素数组的多个批量。

  • SCAN 数组元素是一个键列表。
  • SSCAN 元素数组是 Set 成员的列表。
  • 对于 Hash 的每个返回元素,HSCAN 元素数组包含两个元素,一个字段和一个值。
  • 对于有序集合的每个返回元素,ZSCAN 元素数组包含两个元素,一个成员及其相关分数。

其他例子

迭代一个哈希值。

redis 127.0.0.1:6379> hmset hash name Jack age 33
OK
redis 127.0.0.1:6379> hscan hash 0
1) "0"
2) 1) "name"
   2) "Jack"
   3) "age"
   4) "33"
Redis

Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。 它通常被称为数据结构服务器,因为值( value )可以是 字符串( String ), 哈希(Map),列表(list),集合( sets ) 和 有序集合( sorted sets )等类型。

主页 https://redis.io/
源码 https://github.com/antirez/redis
发布版本 4.0.2

Redis目录

1.集合 | Cluster
2.连接 | Connection
3.Geo
4.Hashes
5.HyperLogLog
6.键 | Keys
7.列表 | Lists
8.Pub/Sub
9.脚本 | Scripting
10.服务器 | Server
11.设定 | Sets
12.排序集 | Sorted Sets
13.字符串 | Strings
14.事务 | Transactions
15.Redis Dump 命令
16.Redis DEL 命令
17.Redis 键(key)
18.Redis 命令
19.Redis 配置
20.Redis 简介
21.Redis RANDOMKEY 命令
22.Redis TTL 命令
23.Redis Pttl 命令
24.Redis PERSIST 命令
25.Redis Move 命令
26.Redis PEXPIREAT 命令
27.Redis Keys 命令
28.Redis Expireat 命令
29.Redis Expire 命令
30.Redis EXISTS 命令
31.Redis Mget 命令
32.Redis Getbit 命令
33.Redis Getset 命令
34.Redis Getrange 命令
35.Redis Get 命令
36.Redis SET 命令
37.Redis 字符串(String)
38.Redis Type 命令
39.Redis Renamenx 命令
40.Redis Rename 命令
41.Redis Incrby 命令
42.Redis Incr 命令
43.Redis Psetex 命令
44.Redis Msetnx 命令
45.Redis Mset 命令
46.Redis Strlen 命令
47.Redis Setrange 命令
48.Redis Setnx 命令
49.Redis Setex 命令
50.Redis Setbit 命令
51.Redis Hincrby 命令
52.Redis Hgetall 命令
53.Redis Hget 命令
54.Redis Hexists 命令
55.Redis Hdel 命令
56.Redis 哈希(Hash)
57.Redis Append 命令
58.Redis Decrby 命令
59.Redis Decr 命令
60.Redis Incrbyfloat 命令
61.Redis Blpop 命令
62.Redis 列表(List)
63.Redis Hvals 命令
64.Redis Hsetnx 命令
65.Redis Hset 命令
66.Redis Hmset 命令
67.Redis Hmget 命令
68.Redis Hlen 命令
69.Redis Hkeys 命令
70.Redis Hincrbyfloat 命令
71.Redis Lrem 命令
72.Redis Lrange 命令
73.Redis Lpushx 命令
74.Redis Lpush 命令
75.Redis Lpop 命令
76.Redis Llen 命令
77.Redis Linsert 命令
78.Redis Lindex 命令
79.Redis Brpoplpush 命令
80.Redis Brpop 命令
81.Redis Sdiff 命令
82.Redis Scard 命令
83.Redis Sadd 命令
84.Redis 集合(Set)
85.Redis Rpushx 命令
86.Redis Rpush 命令
87.Redis Rpoplpush 命令
88.Redis Rpop 命令
89.Redis Ltrim 命令
90.Redis Lset 命令
91.Redis Sunion 命令
92.Redis Srem 命令
93.Redis Srandmember 命令
94.Redis Spop 命令
95.Redis Smove 命令
96.Redis Smembers 命令
97.Redis Sismember 命令
98.Redis Sinterstore 命令
99.Redis Sinter 命令
100.Redis Sdiffstore 命令