为什么不用 HGETALL
HGETALL 会一次性把整个 Hash 拉回客户端,字段多时会长时间占用服务端线程并产生巨大响应;HSCAN 用游标分批返回,每次只处理一小片,服务端与网络都不会被单个大键拖住。用法是 HSCAN key cursor [MATCH pattern] [COUNT n],游标从 0 开始,命令返回的第二个元素再次为 0 时表示遍历结束。
基本信息
| 适用平台 | Redis 2.8.0+ 的 SCAN 家族 |
|---|---|
| 语法 | HSCAN key cursor [MATCH pattern] [COUNT count] |
| 返回值 | 数组:新游标 + 字段与值的交替列表 |
| 结束条件 | 返回的游标为 0 |
| COUNT 语义 | 扫描量的提示值,不保证每次返回的条数 |
典型使用场景
- 清理超大 Hash 中的历史字段,避免 HGETALL 阻塞实例
- 按前缀筛选字段:查某个用户的地址类字段
- 导出或迁移数据:分批读取后写入其他存储
- 巡检大 Hash:估算字段规模,识别需要拆分的键
- 业务变更后遍历补齐新字段
游标遍历与筛选
游标遍历与筛选
HSCAN user:big 0 COUNT 100 # 第一轮:返回新游标与一批字段
# 返回形如:1) "128" 2) 1) "field1" 2) "val1" 3) "field2" 4) "val2"
HSCAN user:big 128 COUNT 100 # 用上一次返回的游标继续
# 直到返回的游标为 0,表示遍历完成
# 只匹配特定前缀的字段
HSCAN user:big 0 MATCH addr:* COUNT 1000
# 客户端脚本里遍历的通用写法(伪代码)
# cursor=0; do { r = HSCAN key cursor COUNT 200; cursor = r[0]; 处理(r[1]); } while (cursor != 0)SCAN 家族对照
| 命令 | 遍历对象 | 常见用途 |
|---|---|---|
| SCAN | 当前库的全部键 | 键清理、大 key 巡检 |
| HSCAN | 一个 Hash 的字段 | 大 Hash 分批导出 |
| SSCAN | 一个 Set 的成员 | 大集合去重与迁移 |
| ZSCAN | 一个 ZSet 的成员与分值 | 排行榜数据导出 |
| MATCH | 过滤模式(可选) | 只取前缀匹配项 |
MATCH 是客户端侧过滤:即使模式只匹配少量字段,服务端仍要扫描 COUNT 提示的量,命中率极低时遍历总耗时不会减少。
SCAN 系列只保证遍历期间一直存在的元素都被返回,期间新增或删除可能造成重复返回,也允许漏掉中途被删除的元素,不能当快照使用。