Redis Key遍历

一.Keys命令:

当数据量较小时,可以使用Keys命令返回所有满足条件的Key集合.但是当数据量较大时,由于此命令通过遍历匹配key所以很容易阻塞Redis服务;另外由于不能使用limit命令,Keys命令会返回所有匹配数据,导致输出过多,所以生产环境一般不使用此命令。

二.Scan命令:

1.优点:
scan命令的时间复杂度虽然也是O(N),但它是分次进行的,不会阻塞线程.
scan命令提供了limit参数,可以控制每次返回结果的最大条数.

2.缺点:
scan返回的数据可能重复(缩容导致的rehash可能重复扫描数据).

3.Redis Key存储结构:
Redis底层key的存储结构就是类似于HashMap那样数组+链表的结构.scan命令就是对这个一维数 组进行遍历。每次返回的游标值也都是这个数组的索引。limit参数表示遍历多少个数组的元素,将这些元素下挂接的符合条件的结果都返回。因为每个元素下挂接的链表大小不同,所以每次返回的结果数量也就不同。

4.scan遍历过程:
SCAN 命令的回复是一个包含两个元素的数组, 第一个数组元素是用于进行下一次迭代的新游标, 而第二个数组元素则是一个数组, 这个数组中包含了所有被迭代的元素.当游标返回值为0时,则表示遍历结束。

5.示例代码:

//批量查询需要统计的数据
Set<String> keys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
     Set<String> keysTmp = new HashSet<>();

     Cursor<byte[]> cursor = connection
             .scan(
                     new ScanOptions.ScanOptionsBuilder()
                             .match(RedisKeyConstant.GLOBAL_PREFIX_KEY + RedisKeyConstant.STAFF_ONLINE_INFO_PREFIX + "*")
                             //count参数在翻译的中文文档中说是返回的数量,但实际应该是每次遍历的哈希槽数量
                             .count(10000L)
                             .build());

     while (cursor.hasNext()) {
         keysTmp.add(new String(cursor.next()));
     }

     return keysTmp;
 });

COUNT:
(1)COUNT参数让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素
(2)COUNT 参数的默认值为 10 。
(3)在迭代一个足够大的、由哈希表实现的数据库、集合键、哈希键或者有序集合键时, 如果用户没有使用 MATCH 选项, 那么命令返回的元素数量通常和 COUNT 选项指定的一样, 或者比 COUNT 选项指定的数量稍多一些。
(4)在迭代一个编码为整数集合(intset,一个只由整数值构成的小集合)、 或者编码为压缩列表(ziplist,由不同值构成的一个小哈希或者一个小有序集合)时, 增量式迭代命令通常会无视 COUNT 选项指定的值, 在第一次迭代就将数据集包含的所有元素都返回给用户。

MATCH:
(1)和 KEYS 命令一样, 增量式迭代命令也可以通过提供一个 glob 风格的模式参数, 让命令只返回和给定模式相匹配的元素, 这一点可以通过在执行增量式迭代命令时, 通过给定 MATCH 参数来实现。

网上有很多地方说上述代码有问题,游标不会移动,需要像下面这么写:
在这里插入图片描述
但实际上只有使用Jedis时才需要这样,使用Redission作为客户端时,仍然可以按照之前的写法,游标可以正常移动,遍历所有数据.

三.参考:
深入理解Redis的scan命令

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐