Redis SCAN 的 COUNT 为什么不是返回条数
来源:17golang原创
时间:2026-10-15 01:22:03 191浏览 收藏
Redis SCAN 的 COUNT 不是“每页返回多少条”的硬性分页参数,而是 Redis 用来估计本次遍历工作量的提示值。一次调用可能返回少于、接近或多于它的元素,也可能返回空集合;真正判断遍历是否结束,要看返回的游标是不是 0。
官方地址:https://redis.io/docs/latest/commands/scan/
把 COUNT 当作每轮工作量提示,把返回游标当作结束信号。即使本轮返回 0 个键,只要游标不是 0,就必须继续调用;如果业务会修改键空间,还要让处理动作可以重复执行。
COUNT 只是提示,不是固定页大小
Redis 官方文档把 COUNT 定义为每次迭代返回元素数量的提示。它影响一次调用大致要做多少遍历工作,但不承诺返回数组的精确长度。默认提示值是 10,调用方还可以在下一轮改变它,只要继续使用上一次返回的游标。
因此,下面这组关系才是正确的理解:
| 观察项 | 正确含义 | 不能推出的结论 |
|---|---|---|
COUNT 100 | 希望 Redis 按大约 100 个元素的工作量推进 | 本次一定返回 100 个键 |
| 本次返回空数组 | 这一轮没有返回可见元素 | 整个遍历已经结束 |
| 返回的游标为 0 | 本轮之后完成一次完整迭代 | 期间没有重复键或变化中的键 |
使用 MATCH | 只筛选返回结果中的匹配键 | Redis 只扫描匹配键 |

先看返回游标,再决定是否继续
一次 SCAN 返回两个部分:下一轮要使用的游标,以及当前轮返回的元素数组。开始时传入 0,之后把新游标原样传回;当新游标再次变成 0 时,一次完整迭代才结束。
用命令行理解这个关系时,可以把每一轮写成下面这样:
# 中文注释:从 0 开始,COUNT 100 只是本轮工作量提示 redis-cli SCAN 0 COUNT 100 # 中文注释:把上一次返回的游标替换到下一轮,不能自行改成 0 redis-cli SCAN COUNT 100 # 中文注释:只有服务端返回游标 0,才表示完整迭代结束 redis-cli SCAN COUNT 100
不要用“本次返回数量小于 COUNT”作为结束条件,也不要因为本轮数组为空就跳出循环。游标和元素数组是两个独立信号:数组说明本轮拿到了什么,游标说明遍历位置是否回到了起点。
MATCH 和 TYPE 会改变结果,但不会改变结束规则
MATCH 用 glob 风格模式筛选返回的键,TYPE 则限定键类型。它们会让某些轮次返回更少的元素,甚至返回空数组,但调用方仍然需要一直传递游标,直到游标为 0。
# 中文注释:先遍历整个键空间,再只返回 cache: 前缀的键 redis-cli SCAN 0 MATCH 'cache:*' COUNT 100 # 中文注释:只返回类型为 hash 的键;过滤条件不会让扫描提前结束 redis-cli SCAN MATCH 'cache:*' TYPE hash COUNT 100
这也是为什么“我设置了 COUNT 100,却只得到 3 个键”不一定是 Redis 出错:键空间可能很小,过滤条件可能很窄,或者这一轮恰好命中了较少的元素。需要关注的是游标是否继续变化,以及最终是否回到 0。

空批次和重复键要按正常情况处理
渐进式遍历的优势是单次调用成本较小,但它不是带快照的分页接口。官方文档明确提醒:一次完整迭代可能返回重复元素;在遍历期间持续新增或删除的键,是否被返回也取决于变化时机。因此清理、同步和统计代码要按“可能重复、可能漏看变化中元素”的模型设计。
常见处理方式有三点:
- 循环条件只绑定返回游标,不绑定本轮元素数量。
- 删除、更新等动作尽量设计成幂等,重复处理同一个键不会造成二次破坏。
- 如果需要严格一致的快照结果,不要把
SCAN当成事务快照或稳定分页器,应该重新设计数据读取方案。
def scan_keys(redis_client, pattern, count=100):
# 中文注释:游标 0 表示从头开始;每轮都使用服务端返回的新游标
cursor = 0
while True:
# 中文注释:count 只影响遍历提示,返回列表长度可以不同
cursor, keys = redis_client.scan(cursor=cursor, match=pattern, count=count)
for key in keys:
# 中文注释:调用方应让后续处理具备幂等性,以容忍重复键
yield key
# 中文注释:空批次不等于结束,游标回到 0 才退出
if cursor == 0:
break
COUNT 应该怎样选
COUNT 的选择本质上是单次响应体积与总调用轮数之间的取舍。值较小,单次返回更轻,但完整遍历可能需要更多调用;值较大,调用次数可能减少,但单次响应、事件循环占用和业务处理压力也会增加。
| 场景 | 建议 | 重点观察 |
|---|---|---|
| 在线请求中顺手查找少量键 | 使用偏小的提示值 | 单次响应延迟和接口超时 |
| 后台清理或迁移 | 逐步调大并限制并发 | Redis 延迟、网络包大小、业务处理速度 |
| 配合 MATCH 过滤 | 从中等值开始观察 | 过滤后的空批次和最终总耗时 |
| 需要严格分页展示 | 不要直接把 SCAN 当分页接口 | 排序、去重和数据一致性需求 |
调大 COUNT 并不会让 SCAN 变成一次性全库读取,也不保证每页固定大小。生产任务还应给循环增加总耗时、每轮处理量或取消信号,避免把一次后台扫描无限期绑在单个任务上。
几个容易混淆的问题
COUNT 设为 1,是否每次只返回一个键?
不是。它仍然只是提示,实际返回数量可能不同,甚至可能是 0。结束条件仍然是返回游标为 0。
返回 0 个键,是否说明 MATCH 没有匹配项?
不能这样判断。当前轮为空可能只是遍历位置暂时没有返回匹配项,继续传递游标后仍可能得到结果;只有完整遍历结束后,才可以把整轮结果合起来判断。
SCAN 能否替代分页查询?
如果页面需要稳定顺序、固定页大小和跨请求一致的结果,SCAN 通常不是合适的分页协议。它更适合渐进式巡检、后台清理、迁移和低阻塞遍历。
总结
记住三句话即可:COUNT 是工作量提示,不是返回条数;数组为空不代表遍历完成;返回游标回到 0 才是一次完整迭代结束。再把过滤条件、重复键和变化中的键空间纳入设计,SCAN 的行为就不会再被“固定分页”模型误读。
-
117 收藏
-
426 收藏
-
171 收藏
-
113 收藏
-
195 收藏
-
454 收藏
-
108 收藏
-
332 收藏
-
291 收藏
-
269 收藏
-
138 收藏
-
495 收藏
-
379 收藏
-
326 收藏
-
110 收藏
-
187 收藏
-
498 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习