您的位置  > 互联网

语法redisSCANSCAN命令及其相关命令-

语法

redis SCAN命令的基本语法如下:

SCAN cursor [MATCH pattern] [COUNT count]

上面列出的四个命令都支持增量遍历。 它们每次执行时只会返回少量元素,因此这些命令在生产环境中使用时不会出现像 KEYS 命令和命令那样的问题 - 当 KEYS 命令用于大型数据库时,或者当命令用于大量密钥,它们可能会阻塞服务器几秒钟。

不过增量遍历命令也不是没有缺点:比如使用该命令可以返回某一时刻set key中包含的所有元素,但是对于SCAN这样的增量遍历命令,因为key是递增的,在这个过程中定量遍历时,key可能会被修改,因此增量遍历命令不能完全保证返回所有元素。

由于 SCAN、SSCAN、HSCAN 和 ZSCAN 这四个命令的工作原理非常相似,因此本文将这四个命令放在一起介绍,但请记住:SSCAN 命令、HSCAN 命令和 ZSCAN 命令的第一个参数始终是一个存储集合的键名。 SCAN 命令不需要在第一个参数中提供任何数据库键 - 因为它会遍历当前数据库中包含的键。

SCAN命令的基本用法

什么是Redis增量遍历? SCAN 命令是基于游标的遍历器。 每次调用时,都会将一个新的光标返回给用户。 用户需要在下次遍历时使用这个新的游标作为SCAN命令的游标参数来继续之前的遍历过程。 。

SCAN 返回一个包含两个元素的数组。 第一个元素是下次遍历的新游标,第二个元素是包含所有遍历元素的数组。 当SCAN命令的游标参数设置为0时,服务器将开始新的遍历,当服务器返回值为0的游标给用户时,表明遍历已经结束。 例如:

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"

上例中,第一次遍历使用0作为光标,表示开始新的遍历。 第二次遍历使用第一次遍历时返回的游标,即命令返回第一个元素的值17。

SCAN命令有效性

然而,由于SCAN命令仅使用游标来记录遍历状态,因此这些命令有以下缺点:

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

SCAN 命令系列不保证每次执行都会返回给定数量的元素。 增量命令甚至可能返回零个元素,但只要该命令返回非 0 的游标,应用程序就不应该认为遍历已完成。

但是,该命令返回的元素数量始终符合一定的规则。 实际应用中:对于大数据集,增量遍历命令每次最多可能返回几十个元素; 对于足够小的数据集,比如小集合键、小哈希键和小有序集键,那么增量遍历命令将在一次调用中返回数据集中的所有元素。

最后,用户可以通过增量遍历命令提供的COUNT选项指定每次遍历返回的元素的最大值。

计数选项

虽然SCAN命令不能保证每次遍历返回的元素数量,但是我们可以使用COUNT选项在一定程度上调整命令的行为。 COUNT 选项的目的是让用户告诉遍历命令每次遍历应从数据集中返回多少个元素。 虽然这个选项只是增量遍历命令的一个提示,但在大多数情况下,这个提示是有效的。

重要提示:并非每次迭代都必须使用相同的 COUNT 值。 用户可以在每次遍历中根据需要自由更改COUNT值,只要记住使用上次遍历返回的游标进行下次遍历即可。

匹配选项

与 KEYS 命令一样,SCAN 命令系列也可以提供 glob 样式模式参数,以允许命令仅返回与给定模式匹配的元素。 这可以通过在执行增量遍历命令时指定 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>

元素的模式匹配是在命令从数据集中检索元素之后并将元素返回给客户端之前的期间执行的。 因此,如果遍历的数据集中只有少量元素与模式匹配,则遍历命令可能在多次执行中都不会返回任何元素。 例如:

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,以强制命令在本次遍历中扫描更多元素,从而使命令返回更多元素。

类型选项

从版本 6.0 开始,您可以使用 TYPE 选项要求 SCAN 仅返回与给定类型匹配的对象,从而允许您迭代数据库查找特定类型的键。 TYPE 选项仅对整个数据库有效 SCAN 命令,对 HSCAN 或 ZSCAN 等没有作用。

请注意一件奇怪的事情,某些 Redis 类型(例如 、 和 )可能在内部使用其他 Redis 类型(例如 或 zset)实现,与 TYPE 命令返回的类型相同。 因此无法通过类型SCAN来区分。 例如,ZSET 和:

redis 127.0.0.1:6379> GEOADD geokey 0 0 value
(integer) 1
redis 127.0.0.1:6379> ZADD zkey 1000 value
(integer) 1
redis 127.0.0.1:6379> TYPE geokey
zset
redis 127.0.0.1:6379> TYPE zkey
zset
redis 127.0.0.1:6379> SCAN 0 TYPE zset
1) "0"
2) 1) "geokey"
   2) "zkey"

需要注意的是,类型过滤器是在从数据库中获取元素之后应用的,因此此选项不会减少服务器完成完整遍历所需的工作量,对于罕见的类型,您可能不会收到任何类型的过滤器。多次遍历。 元素。

同时执行多个遍历

同时,任意数量的客户端都可以遍历同一个数据集。 客户端每次进行遍历时,都需要传入一个游标,执行完遍历后会得到一个新的游标,而这个游标包含了遍历到的所有状态,因此服务端不需要为遍历记录任何状态。

中途停止遍历

由于所有的遍历状态都保存在游标中,并且服务器不需要保存任何遍历状态,因此客户端可以中途停止遍历,而无需通知服务器。 即使任意次数的遍历中途停止,也不会出现问题。

使用错误的游标进行增量遍历

SCAN 使用不连续、负数、超出范围或其他异常游标执行增量遍历不会导致服务器崩溃,但可能会导致命令产生不确定的结果。

只有两种类型的游标是合法的:

保证遍历结束

SCAN命令使用的算法仅保证当数据集的大小有界()时遍历将停止。 换句话说,如果遍历的数据集的大小持续增长,增量遍历命令可能永远不会停止。 无法完成完整的遍历。

直观地可以看出,当数据集不断增长时,需要越来越多的工作来访问数据集中的所有元素。 一次遍历能否结束取决于用户执行遍历的速度是否快于数据集增长的速度。

返回值

SCAN、SSCAN、HSCAN 和 ZSCAN 命令都返回包含两个元素的回复:第一个元素是字符串表示的无符号 64 位整数(游标),第二个元素是本次遍历的元素数组。

历史附加示例

遍历哈希值。

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"

可用版本 >= 2.8.0。

时间复杂度:每次调用 O(1)。 O(N) 表示一次完整的遍历,包括足够的命令调用以使光标返回到 0。N 是集合中元素的数量。