Redis里怎么快速找出带特定开头的那些Key,简单点说就是按前缀筛选所有相关键的方法
- 问答
- 2025-12-30 05:18:47
- 3
这个问题是使用Redis时非常常见的一个需求,你的Redis里存了很多数据,键名可能是这样的:user:1001:profile, user:1002:profile, order:20231001:001, product:abc123,现在你想把所有以 user: 开头的键都找出来,该怎么做呢?
最直接想到的命令可能是 KEYS,这个方法来自Redis官方命令文档。
使用 KEYS 命令
用法非常简单,你只需要在Redis的命令行界面或者通过客户端执行 KEYS user:* 就可以了,这里的星号 是一个通配符,可以匹配任意数量的任意字符。user:* 就能匹配所有以 user: 开头的键。

这个方法听起来很完美,对吧?简单、直接、一次就能拿到所有结果。在生产环境中,强烈不建议使用 KEYS 命令,为什么大家都这么说呢?原因来自Redis本身的工作方式,Redis是单线程的,这意味着它在任何一个时刻只能处理一个命令,当你执行 KEYS 命令时,Redis需要遍历整个数据库的所有键,来找出那些匹配你给出的模式的键,如果你的数据库里存了几百万甚至上千万个键,这个遍历过程会非常耗时,在这段时间里,Redis服务器会被这个 KEYS 命令完全“卡住”,无法处理其他任何请求(比如读取数据、写入数据等),这会导致你的应用程序超时、报错,甚至可能引发服务雪崩,你可以把 KEYS 命令当作一个“扫地僧”,平时在测试环境或者本地开发环境用一下没问题,但千万别在线上服务器(生产环境)去打扰它。
使用 SCAN 命令
既然 KEYS 命令这么危险,那有没有更安全的方法呢?有的,那就是 SCAN 命令,这个方法同样来自Redis官方命令文档,就是为了解决 KEYS 命令的阻塞问题而设计的。

SCAN 命令的工作方式不是一次性的,它像是一个游标式的迭代器,你第一次执行 SCAN 0 MATCH user:*,这里的 0 表示从游标0开始扫描,命令会返回两部分内容:一个是下一次扫描需要用的新游标值(125),另一个是本次扫描匹配到的部分键的列表。
你再用这个新的游标值(125)执行 SCAN 125 MATCH user:*,它又会返回一个新的游标和另一批键,你就这样一遍一遍地执行,直到某一次返回的游标值变回 0,这就表示整个数据库已经扫描完毕,所有匹配的键都已经找出来了。
这个过程虽然看起来比 KEYS 命令麻烦一点,需要执行多次命令,但它的巨大优势在于不会阻塞服务器,每次 SCAN 命令只扫描一小部分数据,然后就把CPU时间让给其他命令,即使数据库非常大,扫描整个过程可能需要好几秒甚至更久,但在这期间的每一刻,Redis都能正常处理其他的插入、查询请求,不会导致服务中断,这是一种“化整为零”的策略。

两种方法的简单对比
你可以这样理解:KEYS 命令就像是你让一个人一口气把一个大仓库里所有红色的箱子都找出来,他必须全神贯注地找,中间不能干别的活,而 SCAN 命令则是让他每次进仓库只找10秒钟,拿出几个红箱子,然后出来处理一下其他人的请求,再进去找10秒钟,如此反复,直到找完,显然后一种方式对整个仓库的运营影响小得多。
实际使用中的小提示
当你使用 SCAN 时,有几点需要注意:
- 重复的可能性:在漫长的扫描过程中,如果数据库的键发生了增减(比如有的键被删除了,或者新的符合前缀的键被加入了),
SCAN命令可能会返回重复的键,也可能某个键会被漏掉,不过对于只是按前缀找键这个需求来说,通常是可以接受一些小概率的重复或遗漏的。 - 编程实现:在实际的代码中(比如用Java的Jedis,Python的redis-py等),客户端库通常都提供了对
SCAN命令的封装,它会帮你处理游标迭代的循环,你只需要提供一个回调函数来处理每一批返回的键,用起来还是很方便的。 - 替代思路:如果你的应用频繁地需要按前缀查询一组键,或许可以考虑一下数据结构的选型,是否可以使用集合(Set)或有序集合(Sorted Set)来专门存储某一类键的名称,每次你存入一个
user:1001:profile时,同时把它加到一個叫user_index的集合里,这样,当你想获取所有用户键时,直接使用SMEMBERS user_index命令就可以了,又快又不会阻塞,但这需要你在写入数据时多做一步操作,是一种用空间换时间、在设计上提前规划的思路。
在Redis里快速(更准确地说是“安全地”)找出带特定前缀的键,正确的做法是使用 SCAN 命令,记住口诀:测试用 KEYS,生产用 SCAN。
本文由歧云亭于2025-12-30发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/71076.html
