一、 keys命令(生产环境禁止使用)
简单粗暴,由于Redis单线程这一特性,keys命令是以阻塞的方式执行的,keys是以遍历的方式实现的复杂度是 O(n),Redis库中的key越多,查找实现代价越大,产生的阻塞时间越长。
keys * 、keys codehole* 分别是查询全部的key以及查询前缀为codehole的key。特点太暴力,性能不好,搜索的是整个redis;
缺点:
1、没有 offset、limit 参数,一次性吐出所有满足条件的 key,万一实例中有几百 w 个 key 满足条件,当你看到满屏的字符串刷的没有尽头时,你就知道难受了。
2、keys 算法是遍历算法,复杂度是 O(n),如果实例中有千万级以上的 key,这个指令就会导致 Redis 服务卡顿,所有读写 Redis 的其它的指令都会被延后甚至会超时报错,因为 Redis 是单线程程序,顺序执行所有指令,其它指令必须等到当前的 keys 指令执行完了才可以继续。
redis的keys命令,通常在用来删除相关的key时使用,但这个命令有一个弊端,在redis拥有数百万及以上的keys的时候,会执行的比较慢,更为致命的是,这个命令会阻塞redis多路复用的io主线程,如果这个线程阻塞,在此执行之间其他的发送向redis服务端的命令,都会阻塞,从而引发一系列级联反应,导致瞬间响应卡顿,从而引发超时等问题,所以应该在生产环境禁止用使用keys和类似的命令smembers,这种时间复杂度为O(N),且会阻塞主线程的命令,是非常危险的。
所以我们通常在生产环境数据量较大的时候,会选择将keys命令做重命名,禁止误操作。
rename-command KEYS ""
官方解释:https://redis.io/commands/KEYS
二、 scan命令(生产环境推荐使用)
以非阻塞的方式实现key值的查找,绝大多数情况下是可以替代keys命令的,可选性更强
scan命令的特点:
1、复杂度虽然也是 O(n),但是它是通过游标分步进行的,不会阻塞线程;
2、提供 limit 参数,可以控制每次返回结果的最大条数,limit 只是一个 hint,返回的结果可多可少;
3、同 keys 一样,它也提供模式匹配功能;
4、服务器不需要为游标保存状态,游标的唯一状态就是 scan 返回给客户端的游标整数;
5、返回的结果可能会有重复,需要客户端去重复,这点非常重要;
正常情况下,使用scan没问题,如果正在rehash,则会造成重读
比如现在有四个桶,读了0,1,发生rehash时, 0会到4上,1是到5,造成重读,
redis使用高位递增遍历,如下, 当02,遍历完以后0426肯定是遍历完的
但缩容有可能发成key重复。
6、遍历的过程中如果有数据修改,改动后的数据能不能遍历到是不确定的;
7、单次返回的结果是空的并不意味着遍历结束,而要看返回的游标值是否为零
Examples:
redis-cli -p 6379 -a password --scan --pattern "name*"
三、DEL命令(生产环境禁止使用)
DEL key [key ...]
删除指定的一批keys,如果删除中的某些key不存在,则直接忽略。
返回值
integer-reply:被删除的keys的数量
Examples
DEL始终在阻止模式下释放值部分.但是,如果该值太大,例如对于大型LIST或HASH的分配太多,它会长时间阻止Redis.
四、unlink 命令(生产环境推荐使用)
unlink key [key ...]
该命令和DEL
十分相似:删除指定的key(s),若key不存在则该key被跳过。但是,相比DEL
会产生阻塞,该命令会在另一个线程中回收内存,因此它是非阻塞的。这也是该命令名字的由来:仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。
返回值
integer-reply:unlink的keys的数量.
Examples
复合查询删除使用样例:
模糊匹配要查询的KEY:
redis-cli -p 6379 -a password --scan --pattern "name*"
将刚刚模糊匹配的KEY异步删除:
redis-cli -p 6379 -a password --scan --pattern "name*"|xargs -L 2000 redis-cli -p 6379 -a password unlink