022、键管理_遍历键

本文介绍了Redis中遍历键的两种方法:全量遍历键的keys命令及其潜在问题,以及渐进式遍历键的scan命令。keys命令虽然方便,但在大量键的情况下可能导致Redis阻塞。相比之下,scan命令通过游标分步遍历,避免了阻塞问题,但可能无法保证完整遍历所有键。同时提到了针对不同数据类型的hscan、sscan和zscan命令。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Redis提供了两个命令遍历所有的键,分别是keys和scan

1.全量遍历键

keys pattern

keys命令是支持pattern匹配的

127.0.0.1:6379> dbsize
(integer) 0
127.0.0.1:6379> mset hello world redis best jedis best hill high
OK

如果要获取所有的键,可以使用keys pattern命令:

127.0.0.1:6379> keys *
1) "hill"
2) "jedis"
3) "redis"
4) "hello"

上面为了遍历所有的键
·*代表匹配任意字符。
·代表匹配一个字符。
·[]代表匹配部分字符,例如[1,3]代表匹配1,3,[1-10]代表匹配1到10的任意数字。
·\x用来做转义,例如要匹配星号、问号需要进行转义。

下面操作匹配以j,r开头,紧跟edis字符串的所有键:

127.0.0.1:6379> keys [j,r]edis
1) "jedis"
2) "redis"

例如下面操作会匹配到hello和hill这两个键:

127.0.0.1:6379> keys hll*
1) "hill"
2) "hello"

当需要遍历所有键时(例如检测过期或闲置时间、寻找大对象等),keys是一个很有帮助的命令,例如想删除所有以video字符串开头的键,可以执行如下操作:
redis-cli keys video* | xargs redis-cli del
但是如果考虑到Redis的单线程架构就不那么美妙了,如果Redis包含了大量的键,执行keys命令很可能会造成Redis阻塞,所以一般建议不要在生产环境下使用keys命令。但有时候确实有遍历键的需求该怎么办,可以在以下三种情况使用:
·在一个不对外提供服务的Redis从节点上执行,这样不会阻塞到客户端的请求,但是会影响到主从复制
·如果确认键值总数确实比较少,可以执行该命令。
·使用下面要介绍的scan命令渐进式的遍历所有键,可以有效防止阻塞。

2.渐进式遍历

命令scan,它能有效的解决keys命令存在的问题。和keys命令执行时会遍历所有键不同,scan采用渐进式遍历的方式来解决keys命令可能带来的阻塞问题,每次scan命令的时间复杂度是O(1),但是要真正实现keys的功能,需要执行多次scan。
在这里插入图片描述

那么每次执行scan,可以想象成只扫描一个字典中的一部分键,直到将字典中的所有键遍历完毕。scan的使用方法如下:
scan cursor [match pattern] [count number]
·cursor是必需参数,实际上cursor是一个游标,第一次遍历从0开始,每次scan遍历完都会返回当前游标的值,直到游标值为0,表示遍历结束。
·match pattern是可选参数,它的作用的是做模式的匹配,这点和keys的模式匹配很像。
·count number是可选参数,它的作用是表明每次要遍历的键个数,默认值是10,此参数可以适当增大。

现有一个Redis有26个键(英文26个字母),现在要遍历所有的键,使用scan命令效果的操作如下。第一次执行scan0,返回结果分为两个部分:第一个部分6就是下次scan需要的cursor,第二个部分是10个键:

127.0.0.1:6379> scan 0
1) "6"
2) 1) "w"
2) "i"
3) "e"
4) "x"
5) "j"
6) "q"
7) "y"
8) "u"
9) "b"
10) "o"

使用新的cursor=“6”,执行scan6:

127.0.0.1:6379> scan 6
1) "11"
2) 1) "h"
2) "n"
3) "m"
4) "t"
5) "c"
6) "d"
7) "g"
8) "p"
9) "z"
10) "a"

这次得到的cursor=“11”,继续执行scan11得到结果cursor变为0,说明所有的键已经被遍历过了:

127.0.0.1:6379> scan 11
1) "0"
2) 1) "s"
2) "f"
3) "r"
4) "v"
5) "k"
6) "l"

除了scan以外,Redis提供了面向哈希类型、集合类型、有序集合的扫描遍历命令,解决诸如hgetall、smembers、zrange可能产生的阻塞问题,对应的命令分别是hscan、sscan、zscan,它们的用法和scan基本类似,下面以sscan为例子进行说明,当前集合有两种类型的元素,例如分别以old:user
和new:user开头,先需要将old:user开头的元素全部删除,可以参考如下伪代码:

String key = "myset";
// 定义pattern
String pattern = "old:user*";
// 游标每次从0开始
String cursor = "0";
while (true) {
// 获取扫描结果
ScanResult scanResult = redis.sscan(key, cursor, pattern);
List elements = scanResult.getResult();
if (elements != null && elements.size() > 0) {
// 批量删除
redis.srem(key, elements);
}
// 获取新的游标
cursor = scanResult.getStringCursor();
// 如果游标为0表示遍历结束
if ("0".equals(cursor)) {
break;
}
}

渐进式遍历可以有效的解决keys命令可能产生的阻塞问题,但是scan并非完美无瑕,如果在scan的过程中如果有键的变化(增加、删除、修改),那么遍历效果可能会碰到如下问题:新增的键可能没有遍历到,遍历出了重复的键等情况,也就是说scan并不能保证完整的遍历出来所有的键

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值