一、概述
在redis中,我们经常通过keys命令,来查看当前redis中键,它是一个相当不错的命令,格式如下:KEYS pattern
比如:
KEYS * 匹配数据库中所有 key 。
KEYS fi?d 匹配单个字符,如find、fied等
KEYS find*.wang 匹配一个或多个字符,比findme.wang
KEYS fin[de]me 匹配指定的字符,即匹配findme或fineme。
最近有个需求,需要删除redis中旧数据,其中键中含有日期,如下:

我想把3天前的数据,都删除,怎么搞呢?
首先,我想到的是通过key hash.out.*,匹配出该类型的所有key,然后提取key中的日期,根据提取的日期做删除操作。
发现既然报错:
(error) ERR unknown command 'key'
原来当数据规模较大时使用,KEYS命令,会严重影响Redis性能,也非常危险,于是被禁用掉了。
既然key命令没了,只能能够scan命令来解决。
二、scan命令
SCAN 命令是一个基于游标的迭代器(cursor based iterator),每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束。
scan命令格式如下:SCAN cursor [MATCH pattern] [COUNT count]
参数描述:
cursor,即游标;
MATCH pattern 匹配的格式,和keys命令匹配类似;
COUNT count 就是让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素
三、解决方案
通过scan命令的了解,我们是可以通过scan命令来解决问题的。命令格式如下:scan 0 MATCH hash.out.*
这样就可以匹配出一hash.out.开头的key
php的实现如下:$index = 0;
$matchKey = 'hash.out.*';
$data = $redis->scan($index, ['MATCH', $matchKey]);
if (empty($data)) {
return;
}
$nextId = array_shift($data);
$data = array_shift($data);
while ($nextId != $index) {
//删除旧数据
foreach ($data as $curKey) {
if (empty($curKey)) {
continue;
}
$curDay = end(explode('.', $curKey));
if ($twoDaysAgo > $curDay) {
//删除当前key
$redis->del($curKey);
}
}
$data = $redis->scan($nextId, ['MATCH', $matchKey]);
if (empty($data)) {
break;
}
$nextId = array_shift($data);
$data = array_shift($data);
}