版权声明: 转载请注明出处!本文采用 知识共享 署名-非商业性使用-禁止演绎 4.0 国际许可协议
前言
今天是不是感觉有点奇怪,这篇笔记只讲了一个命令 SCAN,这是到目前为止,唯一只讲一个命令的一篇笔记,原因就是这个命令的官方文档是在太长了,我光看明白它是干嘛的就花费了很长时间,然后再一个个尝试参数,最后决定单独给它写一篇吧。
其实它有很多兄弟姐妹,比如 hscan, sscan, zscan等等,用法很类似,可以相互借鉴,这篇笔记就重点讲一下基础的 SCAN。
KEYS
- 最早出现版本:2.8.0
- 时间复杂度:O(1) (对于每次调用来说,完整一次迭代是O(N))
- 命令参数:SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
- 操作类型:keys
- 官方文档
作用
文档上的描述内容很长,但是可以总结一句话,那就是分段的遍历整个数据库中的键。
前一篇《Redis每日一练(14):KEYS、TYPE和RENAME命令》说到 KEYS 命令最好不要什么地方都用,它虽然可以对数据库中的键进行一次完整的迭代,但是面对大量数据的时候会有性能问题,所以最好用在调试或者一些特殊的地方。
而今天的 SCAN 命令就可以弥补 KEYS 命令的不足,反复调用 SCAN 命令不会引起性能问题,它仿佛就是把 KEYS 命令拆分成几个小段来执行的。
说到这可能有些人会想到,如果将一次完整的迭代分成若干个小段来进行,那中间有些键发生变化,结果不就变了吗?这个疑惑很有必要,结果也是和想的一样,Redis 对于 SCAN 命令只做有限的保证,它只能保证你完整的做完一次迭代期间,如果一个键的存在性没有发生变化,那它可能出现在结果集中,如果是中途添加或删除的键,可能出现在结果集也可能不出现。
基本用法
SCAN 命令的迭代类似一个链式调用,每次迭代开始必须从 0 这个游标启动,每次结果返回包括两部分,第一部分是下一次命令需要调用的游标,第二部分是本地调用得到的键的列表,依次执行下去,直到返回值的第一部分变成0则表示进行了一次完整的迭代。
这个命令可以和 KEYS命令进行一个对比,先调用一次 KEYS 命令列出数据库中所有的键:
127.0.0.1:6379> KEYS *
1) "user"
2) "score"
3) "num"
4) "key"
5) "count"
6) "name"
7) "length"
8) "namr"
9) "address"
10) "test"
11) "str"
12) "weight"
13) "user:1001"
127.0.0.1:6379>
在调用 SCAN 命令完成一次完整的迭代:
127.0.0.1:6379> SCAN 0
1) "13"
2) 1) "user"
2) "score"
3) "num"
4) "name"
5) "length"
6) "count"
7) "test"
8) "str"
9) "weight"
10) "key"
127.0.0.1:6379> SCAN 13
1) "0"
2) 1) "namr"
2) "address"
3) "user:1001"
查看调用结果,一共使用了两次 SCAN 命令才完成了一次完整的迭代,查询到的结果集与 KEYS 命令查询到的一样,第一次查询返回的第一个结果作为第二次查询的参数,完整了迭代的延续。
MATCH pattern
这个参数类似于讲 EKYS 命令时的匹配规则,这个模式串可以指定匹配的规则,我可以把这部分内容在展示一次。
*
可以匹配任意长字符,例n*me
可以匹配nme
、name
、nzzme
等等?
可以匹配一个任意字符,例如n?me
可以匹配name
、nzme
,但是无法匹配nabme
,因为多了一个字符[ad43]
可以表示匹配可选集,例如n[ab]me
只可以匹配name
和nbme
,无法再匹配其他的[0-9]
是上一种的简写方式,代表了[0123456789],其他范围也可以简写,比如匹配小写字母[a-z][^ab]
反向匹配,匹配集合中出现^
表示不匹配集合中的内容,例n[^ab]me
可以匹配nzme
,但无法匹配name
有了这些说明,我们可以使用 SCAN 命令来遍历一次以n开头的键:
127.0.0.1:6379> SCAN 0 MATCH n*
1) "13"
2) 1) "num"
2) "name"
127.0.0.1:6379> SCAN 13 MATCH n*
1) "0"
2) 1) "namr"
COUNT count
这个参数可以指定每次迭代最大返回数量,虽然只是一种暗示,但是它经常是有效的,关于数量默认最大值是10,但是每次返回的键的数量可以是0,数量为0并不意味着迭代结束,结束条件只有一个,那就是返回的游标为0。
我们制定COUNT参数为5时看一下返回结果:
127.0.0.1:6379> SCAN 0 COUNT 5
1) "6"
2) 1) "user"
2) "score"
3) "num"
4) "name"
5) "length"
127.0.0.1:6379> SCAN 6 COUNT 5
1) "13"
2) 1) "count"
2) "test"
3) "str"
4) "weight"
5) "key"
127.0.0.1:6379> SCAN 13 COUNT 5
1) "0"
2) 1) "namr"
2) "address"
3) "user:1001"
TYPE type
这个参数是6.0版本才加上的,用来返回指定类型的键,比如返回字符串类型的键可以使用TYPE string
,当然在我这个3.2.100这个版本加上这个参数是会报错的:
127.0.0.1:6379> SCAN 0 TYPE string
(error) ERR syntax error
总结
- SCAN 命令将 KEYS 命令的完整迭代划分成了分段迭代,避免了过长时间的阻塞服务器。
- 在同一时间,可以有任意多个客户端对同一数据集进行迭代,迭代的状态记录在游标中,服务器无需记录状态。
2019-12-4 20:42:04