Redis里怎么快点找出想要的keys,别用慢方法了
- 问答
- 2026-01-14 21:27:14
- 1
想在Redis里快点找出想要的keys,核心就一句话:尽量避免在生产环境直接用 KEYS 命令,这是所有Redis老手和新手都必须记住的第一条军令,下面我详细说说为什么,以及用什么方法来替代。
第一部分:为什么 KEYS 命令是“慢方法”的典型?
(来源:Redis官方文档在 KEYS 命令说明中的明确警告)
KEYS 命令的问题在于它的工作方式是“阻塞式”和“全表扫描”,你可以把Redis的数据库想象成一个巨大的、没有目录的字典,当你在客户端输入 KEYS user:123* 这个命令时,Redis服务器会做一件很可怕的事情:它会暂停所有其他操作,然后一页一页地、从头到尾翻遍整个字典,把所有符合 user:123* 这个模式的键找出来,再一次性返回给你。
这个过程有两个致命伤:
- 阻塞: 在Redis翻字典的这段时间里(可能几毫秒,也可能几秒甚至更长,取决于你的数据量),整个Redis服务器是无法响应其他任何读写命令的,这会导致你的应用程序卡住,超时,对于高并发的线上服务来说,这简直是灾难,官方文档直接说它“可能使服务器挂起数秒”。
- 性能随数据量线性下降: 你的数据库里有100个key,
KEYS命令可能瞬间完成,但有100万个key呢?1000万个key呢?它的速度会越来越慢,因为每次都是检查所有key。
KEYS 命令只应该用在测试环境、数据量极小或者你明确知道可以接受服务短暂不可用的情况下。 线上环境绝对不要用。
第二部分:推荐的快方法——使用 SCAN 命令
(来源:Redis官方文档为解决 KEYS 命令问题而引入的 SCAN 系列命令)
既然KEYS是“一口气翻完字典”,那SCAN命令就是“分批分次地翻字典”,它解决了KEYS命令的两个核心痛点。
SCAN 命令的基本用法是 SCAN cursor [MATCH pattern] [COUNT count]。
cursor是一个游标,第一次遍历时设为0,表示开始一次新的迭代。MATCH pattern和KEYS命令后面的模式一样,用于匹配键名。COUNT count是建议每次迭代返回多少元素,注意这只是个“建议值”,Redis不一定完全遵守,但大体上每次返回的数量会在这个值附近。
它的工作流程是这样的:
- 你第一次调用
SCAN 0 MATCH user:* COUNT 100,Redis会从数据库里扫描大概100个key,然后把满足user:*模式的key返回给你,同时返回一个新的游标值,65。 - 你接着调用
SCAN 65 MATCH user:* COUNT 100,Redis会从上次停止的地方(游标65的位置)继续扫描大概100个key,再返回结果和一个新的游标。 - 如此反复,直到Redis返回的游标是
0,这表示整个数据库已经遍历完毕,所有匹配的key你都拿到了。
SCAN 快在哪里?
- 非阻塞: 每次调用
SCAN都只花费很短的时间,不会长时间阻塞服务器,其他客户端的请求可以在两次SCAN调用的间隙得到处理,虽然整个遍历过程的总耗时可能比一次性的KEYS命令还要长,但它把时间碎片化了,不影响整体服务的可用性。 - 可控的消耗: 你可以通过
COUNT参数来控制每次扫描的强度,根据服务器的繁忙程度灵活调整。
第三部分:使用 SCAN 需要注意的细节
(来源:Redis官方文档对 SCAN 命令特性的说明)
- 重复与遗漏:
SCAN命令在遍历过程中,如果数据库有增删改,可能会出现某个key被返回多次或者一次都没返回的情况,这是因为它是基于游标的增量迭代,无法提供完整的快照保证,如果你的应用场景要求遍历过程中数据绝对一致(比如精确统计),SCAN可能不太适合,但对于大多数“找出key并处理”的场景,这个缺点是可以接受的。 - 不止一种
SCAN: 除了遍历所有key的SCAN,Redis还提供了针对特定数据结构的遍历命令:SSCAN用于遍历集合(Set)中的元素。HSCAN用于遍历哈希(Hash)中的所有字段和值。ZSCAN用于遍历有序集合(Sorted Set)中的成员和分值。 当你需要处理大集合、大哈希时,也应该使用这些命令来替代SMEMBERS、HGETALL等可能阻塞服务器的命令。
第四部分:从根本上提速——好的设计优于任何命令
(来源:基于Redis最佳实践的普遍认知)
最高级的“快方法”不是等数据存进去了再想办法找,而是在设计阶段就避免大规模的模式匹配查询,Redis本质上是键值存储,最擅长的就是通过明确的key直接获取value,频繁使用 SCAN 或 KEYS 往往意味着数据模型设计可以优化。
- 使用索引集合: 这是最有效的方法,你想快速找到所有
user:123:开头的key(user:123:profile,user:123:orders),你可以在创建这些key的同时,也往一个叫index:user:123的集合(Set)里添加这些key的名称(或它们的部分标识),这样,当你需要找所有属于用户123的key时,直接SMEMBERS index:user:123就行了,速度极快,复杂度是O(1),这相当于你自己手动维护了一个“目录”。 - 合理设计键名: 如果不同的数据有关联,可以把关联信息设计在键名里,把用户ID和订单ID组合成
order:{userId}:{orderId},这样虽然你还是需要SCAN,但你的匹配模式可以更精确,扫描范围更小。 - 考虑其他工具: 如果你需要非常复杂的查询,比如范围查询、多条件组合查询,那可能Redis本身就不是最合适的工具,可以考虑使用RedisJSON模块,或者将数据同步到专门的搜索数据库(如Elasticsearch)中进行处理。
- 绝对禁止在线上环境使用
KEYS命令。 - 需要遍历或模式匹配时,首选
SCAN系列命令,它通过非阻塞、分批的方式解决了性能问题。 - 最高境界是通过良好的数据模型设计(如使用索引集合),从根本上避免大规模的模式匹配,让查询永远是通过直接键名访问,这才是最快的方案。

本文由度秀梅于2026-01-14发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/80772.html
