Redis遍历所有key的两个命令 -- KEYS 和 SCAN
当我们需要遍历Redis所有key或者指定模式的key时,首先想到的是KEYS命令:
KEYS pattern
官网对于KEYS命令有一个提示: KEYS 的速度非常快,例如,Redis在一个有1百万个key的数据库里面执行一次查询需要的时间是40毫秒 。但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的 KEYS, 你最好还是用 Redis 的集合结构 SETS 来代替。
- redis> MSET one 1 two 2 three 3 four 4
- OK
- redis> KEYS *o*
- 1) "four"
- 2) "one"
- 3) "two"
- redis> KEYS t??
- 1) "two"
- redis> KEYS *
- 1) "four"
- 2) "three"
- 3) "one"
- 4) "two"
- redis>
但由于KEYS命令一次性返回所有匹配的key,所以,当redis中的key非常多时,对于内存的消耗和redis服务器都是一个隐患,
SCAN cursor [MATCH pattern] [COUNT count]
SCAN 每次执行都只会返回少量元素,所以可以用于生产环境,而不会出现像 KEYS 或者 SMEMBERS 命令带来的可能会阻塞服务器的问题。
SCAN命令是一个基于游标的迭代器。这意味着命令每次被调用都需要使用上一次这个调用返回的游标作为该次调用的游标参数,以此来延续之前的迭代过程
当SCAN命令的游标参数(即cursor)被设置为 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 命令时, 命令返回了游标 0 , 这表示迭代已经结束, 整个数据集已经被完整遍历过了。
full iteration :以 0 作为游标开始一次新的迭代, 一直调用 SCAN 命令, 直到命令返回游标 0 , 我们称这个过程为一次完整遍历。
SCAN增量式迭代命令并不保证每次执行都返回某个给定数量的元素,甚至可能会返回零个元素, 但只要命令返回的游标不是 0 , 应用程序就不应该将迭代视作结束。
不过命令返回的元素数量总是符合一定规则的, 对于一个大数据集来说, 增量式迭代命令每次最多可能会返回数十个元素;而对于一个足够小的数据集来说,可能会一次迭代返回所有的key
COUNT选项
对于增量式迭代命令不保证每次迭代所返回的元素数量,我们可以使用COUNT选项, 对命令的行为进行一定程度上的调整。COUNT 选项的作用就是让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素。使用COUNT 选项对于对增量式迭代命令相当于一种提示, 大多数情况下这种提示都比较有效的控制了返回值的数量。
注意:COUNT选项并不能严格控制返回的key数量,只能说是一个大致的约束。并非每次迭代都要使用相同的 COUNT 值,用户可以在每次迭代中按自己的需要随意改变 COUNT 值, 只要记得将上次迭代返回的游标用到下次迭代里面就可以了。
MATCH 选项
类似于KEYS 命令,增量式迭代命令通过给定 MATCH 参数的方式实现了通过提供一个 glob 风格的模式参数, 让命令只返回和给定模式相匹配的元素。
MATCH 选项对元素的模式匹配工作是在命令从数据集中取出元素后和向客户端返回元素前的这段时间内进行的, 所以如果被迭代的数据集中只有少量元素和模式相匹配, 那么迭代命令或许会在多次执行中都不返回任何元素。
以下是这种情况的一个例子:
- 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 , 强制命令为本次迭代扫描更多元素, 从而使得命令返回的元素也变多了。
- <?php
- $redis = new Redis();
- $redis->connect('127.0.0.1', 6379);
- /* 设置遍历的特性为不重复查找,该情况下扩展只会scan一次,所以可能会返回空集合 */
- $redis->setOption(Redis::OPT_SCAN, Redis::SCAN_NORETRY);
- $it = NULL;
- $pattern = '*';
- $count = 50; // 每次遍历50条,注意是遍历50条,遍历出来的50条key还要去匹配你的模式,所以并不等于就能够取出50条key
- do
- {
- $keysArr = $redis->scan($it, $pattern, $count);
- if ($keysArr)
- {
- foreach ($keysArr as $key)
- {
- echo $key . "\n";
- }
- }
- } while ($it > 0); //每次调用 Scan会自动改变 $it 值,当$it = 0时 这次遍历结束 退出循环
- echo '---------------------------------------------------------------------------------' . "\n";
- /* 设置扩展在一次scan没有查找出记录时 进行重复的scan 直到查询出结果或者遍历结束为止 */
- $redis->setOption(Redis::OPT_SCAN, Redis::SCAN_RETRY);
- $it = NULL;
- $pattern = '*';
- $count = 50; // 每次遍历50条,注意是遍历50条,遍历出来的50条key还要去匹配你的模式,所以并不等于就能够取出50条key
- //这种用法下我们只需要简单判断返回结果是否为空即可, 如果为空说明遍历结束
- while ($keysArr = $redis->scan($it, $pattern, $count))
- {
- foreach ($keysArr as $key)
- {
- echo $key . "\n";
- }
- }
- [root@localhost php]# /usr/local/php/bin/php scan.php
- bm
- bm2
- h1
- name
- bit
- bm1
- places
- cities
- hhl
- ---------------------------------------------------------------------------------
- bm
- bm2
- h1
- name
- bit
- bm1
- places
- cities
- hhl
Redis遍历所有key的两个命令 -- KEYS 和 SCAN的更多相关文章
- Redis系列之key操作命令与Redis中的事务详解(六)
序言 本篇主要目的有二: 1.展示所有数据类型中key的所有操作命令,以供大家学习,查阅,更深入的挖掘redis潜力. 2.掌握redis中的事务,让你的数据完整性一致性拥有更优的保障. redis命 ...
- 如何解决Redis中的key过期问题
最近我们在Redis集群中发现了一个有趣的问题.在花费大量时间进行调试和测试后,通过更改key过期,我们可以将某些集群中的Redis内存使用量减少25%. Twitter内部运行着多个缓存服务.其中一 ...
- Redis批量删除key的小技巧,你知道吗?
在使用redis的过程中,经常会遇到要批量删除某种规则的key,但是redis提供了批量查询一类key的命令keys或scan,没有提供批量删除某种规则key的命令,怎么办?看完本文即可,哈哈. 本文 ...
- redis的hash, list, set类型相关命令
hash相关命令: 1. hset HSET key field value 将哈希表key中的域field的值设为value.如果key不存在,一个新的哈希表被创建并进行hset操作.如果域fiel ...
- Redis进阶实践之十五 Redis-cli命令行工具使用详解第二部分(结束)
一.介绍 今天继续redis-cli使用的介绍,上一篇文章写了一部分,写到第9个小节,今天就来完成第二部分.话不多说,开始我们今天的讲解.如果要想看第一篇文章,地址如下:http: ...
- Redis实战 - 4.Key
Redis 键(key) Redis 键命令用于管理 redis 的键. DEL key 该命令用于在 key 存在时删除 key. 127.0.0.1:6379> set w3ckey red ...
- redis 中的key值过期后,触发通知事件
1.创建springboot工程,创建监听类 maven配置 <dependencies> <dependency> <groupId>org.springfram ...
- Redis进阶实践之十四 Redis-cli命令行工具使用详解
转载来源:http://www.cnblogs.com/PatrickLiu/p/8508975.html 一.介绍 redis学了有一段时间了,以前都是看视频,看教程,很少看官方的东西.现在redi ...
- redis push/pop(List)的17条命令
一.Blpop 命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止.redis 127.0.0.1:6379> BLPOP LIST1 LIST2 .. ...
随机推荐
- linux之touch命令修改文件的时间戳
功能:对已经存在文件的时间进行修改,存取时间(access time).修改时间(modification time).对不存在的文件,进行创建新的空白文件. 语法:touch [选项] 文件 ...
- android BSP与硬件相关子系统读书笔记(1)android BSP移植综述
从linux驱动转行至Android驱动开发大半年了,一开始就产生了一个很纠结目标和问题,就是不停的google如何porting android!这个问题得到的结果对于初出茅庐的我,感到迷惘.随着工 ...
- gcc static静态编译选项提示错误:/usr/lib/ld:cannot find -lc
在学习gcc静态库动态库编译的时候选用静态库编译时出错显示:/usr/lib/ld:cannot find -lc 百度:/usr/lib/ld:cannot find -lc多处给的解决方案为: 然 ...
- Concise: Compressed ’n’ Composable Integer Set
Word Aligned Hybrid (WAH) bitmap compression 下面是:Concise: Compressed ’n’ Composable Integer Set Figu ...
- web开发者的博客
一. Jerry Qu https://imququ.com/post/sth-about-switch-to-https-2.html 点评:博客做的比较好,样式不错. http知识比较深.
- angular学习(二)—— Data Binding
转载请写明来源地址:http://blog.csdn.net/lastsweetop/article/details/51182106 Data Binding 在angular中.model和vie ...
- [Flutter] Creating, Importing & Using Dynamic Widgets from Other Files in a Flutter Application
In this lesson we’ll learn how to import widgets we’ve created in other files & use them in our ...
- 【IE兼容性】background:transparent IE中Bug,不能选中input输入框,出现这个问题主要是IE8
先解释下,background:transparent,默认在IE上会被解析成 background: none transparent scroll repeat 0% 0% transparent ...
- JavaScript 查看函数调用栈
1.调用栈 js中的this与函数调用栈密切相关. this实在函数调用时发生的绑定,它指向完全取决于函数在哪里被调用. 2.示例 <!DOCTYPE html> <html ...
- Cocos2dx 3.6源代码编译错误:syntax error : missing ')' before '{'
在编译Cocos2dx 3.6版本号时.发现编译错误: 定位代码行: debugForNormalSprite->drawPoints(positions, 4, 8, Color4F{0.0, ...