Redis SCARD 命令详细教程
SCARD 返回集合(Set)中成员的数量(基数,cardinality)。它从 Redis 1.0.0 起提供,复杂度为 O(1),因为 Redis 在集合内部直接维护了成员计数,不需要遍历。SCARD 常用于去重计数、判断集合是否为空、监控集合规模,是集合类型最轻量的查询命令。
资料合集:https://pan.quark.cn/s/10e98d308913、https://pan.quark.cn/s/f56bc69c5338
一、概览与语法
redis
SCARD key
| 项目 | 说明 |
|---|---|
| 数据类型 | Set |
| 支持版本 | Redis 1.0.0 起 |
| key | 目标集合 Key |
| 参数个数 | 仅一个 Key,不接受任何选项 |
| 返回值 | 整数,集合中的成员数量;Key 不存在时返回 0 |
| 时间复杂度 | O(1) |
| ACL | @read、@set、@fast |
| 命令标记 | readonly、fast |
官方说明:返回存储在 key 的集合的基数(成员数量)。$TRAE_REF
集合的最大成员数为 2^32 - 1(超过 42 亿),因此 SCARD 的返回值范围是 0 到 2^32 - 1。
二、基础示例
以下命令在测试实例的 redis-cli 中执行。文中结果是预期说明,未实际连接 Redis 运行。示例沿用官方文档的数据与结果。
redis
DEL tutorial:{scard}:myset
SADD tutorial:{scard}:myset "Hello"
SADD tutorial:{scard}:myset "World"
SCARD tutorial:{scard}:myset
预期结果:两条 SADD 各返回 1;SCARD 返回 (integer) 2。
三、返回值与空结果
SCARD 的返回值语义简单而确定:永远返回整数,不会返回空值。
| 情形 | 返回 |
|---|---|
| Key 存在且是集合 | 成员数量(正整数) |
| Key 不存在 | 0 |
| Key 是其他类型 | 报 WRONGTYPE(不返回 0) |
由此可得一个重要结论:SCARD key == 0 等价于该集合 Key 不存在。Redis 中不存在"空集合 Key"------最后一个成员被 SREM 或 SPOP 移除后,Key 会被立即删除。这与 LLEN 返回 0 等价于列表 Key 不存在是同一套模型。
redis
DEL tutorial:{scard}:empty
SCARD tutorial:{scard}:empty
EXISTS tutorial:{scard}:empty
预期结果:SCARD 返回 0;EXISTS 返回 0,二者互相印证。
四、去重计数与 SADD 返回值的配合
SCARD 常与 SADD 的返回值配合,实现"本次新增了多少、累计多少"的统计:
redis
DEL tutorial:{scard}:uv
SADD tutorial:{scard}:uv u1 u2 u3
SCARD tutorial:{scard}:uv
SADD tutorial:{scard}:uv u3 u4
SCARD tutorial:{scard}:uv
预期结果:第一条 SADD 返回 3,SCARD 返回 3;第二条 SADD 传入 u3、u4,其中 u3 已存在,返回 1,SCARD 随后返回 4。
SADD 的返回值是本批次新增数,SCARD 是累计总数,两者含义不同,不要混用。SCARD 本身不会告诉你"最近新增了什么",只给出总数。
五、边界情况与错误处理
| 场景 | 行为 |
|---|---|
| Key 不存在 | 返回 0,不报错、不创建 Key |
| Key 类型不是 Set | 报 WRONGTYPE |
| 缺少 Key 参数 | 报语法错误 |
| 提供多余参数 | 报 ERR wrong number of arguments for 'scard' command |
| Key 设置了 TTL 且未过期 | 正常返回数量,TTL 不受影响 |
redis
SET tutorial:{scard}:str text
SCARD tutorial:{scard}:str
SCARD
预期结果:对 String 类型执行报 WRONGTYPE;不传 Key 报 ERR wrong number of arguments for 'scard' command。
六、与相近命令的区别
SCARD 属于各数据类型"长度/基数"命令家族,用法一致,只是作用对象不同:
| 命令 | 作用类型 | 返回 | 复杂度 |
|---|---|---|---|
| SCARD | Set | 集合成员数量 | O(1) |
| LLEN | List | 列表元素数量 | O(1) |
| HLEN | Hash | 哈希字段数量 | O(1) |
| STRLEN | String | 字符串字节长度 | O(1) |
| ZCARD | Sorted Set | 有序集合成员数量 | O(1) |
| XLEN | Stream | 流中消息条数 | O(1) |
与集合内其他命令的区别:
| 命令 | 与 SCARD 的区别 |
|---|---|
| SMEMBERS | 返回全部成员内容,O(N),大集合上是慢命令 |
| SSCAN | 游标迭代成员,不阻塞,适合大集合遍历 |
| SISMEMBER | 判断单个成员是否存在,返回 0/1 |
| SMISMEMBER | 批量判断成员是否存在,6.2.0 起 |
| SRANDMEMBER | 随机取成员,不改变集合 |
| SCARD | 只返回数量,O(1),最轻量 |
只想得到数量时用 SCARD,不要用 SMEMBERS 再取长度------后者会把全部成员传输到客户端,在百万级集合上既慢又占带宽。
七、客户端示例
前提为已安装 redis-py 并准备好本地测试实例。redis-py 的 scard(name) 返回整数。
python
import redis
r = redis.Redis(host="localhost", port=6379, decode_responses=True)
key = "tutorial:{scard}:py"
try:
r.delete(key)
print(r.scard(key)) # 0,Key 不存在
r.sadd(key, "a", "b", "c")
print(r.scard(key)) # 3
r.sadd(key, "c", "d")
print(r.scard(key)) # 4,c 重复被忽略
r.srem(key, "a", "b", "c", "d")
print(r.scard(key)) # 0,成员移除完 Key 被删除
print(r.exists(key)) # 0
finally:
r.delete(key)
r.close()
Java(Jedis)示例,scard(key) 返回 long:
java
try (Jedis jedis = new Jedis("localhost", 6379)) {
String key = "tutorial:{scard}:java";
jedis.del(key);
System.out.println(jedis.scard(key)); // 0
jedis.sadd(key, "a", "b", "c");
System.out.println(jedis.scard(key)); // 3
jedis.sadd(key, "c", "d");
System.out.println(jedis.scard(key)); // 4
jedis.del(key);
}
八、原子性与并发
只读且原子:SCARD 不修改数据,单命令原子,返回某一瞬间的精确计数。可在副本节点读取以分担主节点压力。
"先查数量再操作"存在竞态 :SCARD 判断大于 0 后再 SPOP,两步之间集合可能已被其他客户端清空。不要用 if SCARD > 0 then SPOP 作为并发安全保证;直接调用 SPOP 并处理空值返回,或用 Lua 脚本合并判断与操作。
计数是精确值:SCARD 返回真实成员数,没有误差。这一点与 HyperLogLog 的 PFCOUNT 不同------后者用约 12 KB 内存估算基数,存在约 0.81% 的标准误差,换来的是极低的内存占用。选择规则:需要精确数量且成员集合本身要保留,用 Set + SCARD;只需要近似 UV 且内存敏感,用 HyperLogLog。
事务与 Pipeline:可在 MULTI/EXEC、Lua 脚本与管道中正常使用;批量统计多个集合规模时用管道一次发出。
九、性能与使用注意事项
恒为 O(1):Redis 在集合对象内部维护了计数,读取不随成员数增长,百万级集合与个位数集合的 SCARD 耗时相同。可安全高频调用。
不产生副作用:不创建 Key、不改 TTL、不影响内容。
注意编码变化不影响结果:集合在成员全为整数且数量较少时用 intset 编码,否则用 hashtable 编码,但两种编码下 SCARD 都是 O(1),返回值一致。
与内存估算区分 :SCARD 是数量,不是内存占用。评估内存要看集合的编码与成员长度,可用 MEMORY USAGE key 查询。
十、典型业务场景
UV 去重统计:把访问用户 ID SADD 进按天命名的集合,用 SCARD 得到当日去重访客数。数据量大时改用 HyperLogLog 节省内存。
在线用户数:用户上线 SADD、下线 SREM,SCARD 即当前在线人数,O(1) 读取,适合高频刷新的大屏展示。
黑白名单规模监控:定期 SCARD 观察名单增长,异常膨胀时告警。
抽奖池容量判断:抽奖前用 SCARD 确认剩余奖品数量,为 0 则停止活动。
唯一性约束的辅助判断:SADD 返回 0 表示已存在,配合 SCARD 可统计累计注册数等。
十一、练习、排错与总结
练习:新建 tutorial:{scard}:ex,先执行 SCARD ex 确认返回 0 且 EXISTS 为 0;SADD 加入 a b c 后确认 SCARD 返回 3;再 SADD c d,确认 SADD 返回 1、SCARD 返回 4;SREM 移除全部四个成员后确认 SCARD 返回 0 且 EXISTS 为 0;用 SET 把该 Key 改成 String 后执行 SCARD,确认报 WRONGTYPE。
排错要点:SCARD 返回 0 表示集合 Key 不存在(空集合不会以 Key 形式存在),配合 EXISTS 确认;报 WRONGTYPE 时用 TYPE 检查 Key 是否被其他类型占用;把 SCARD 当作并发安全的前置检查会引发竞态,应改用原子命令;需要成员内容时 SCARD 无法提供,应使用 SMEMBERS 或 SSCAN;需要近似基数且内存敏感时改用 PFADD/PFCOUNT;统计值与预期不符时检查是否有重复成员被忽略(SADD 去重)。清理使用 DEL tutorial:{scard}:myset tutorial:{scard}:empty tutorial:{scard}:uv tutorial:{scard}:str tutorial:{scard}:py tutorial:{scard}:java tutorial:{scard}:ex。速记:1.0 起支持、返回集合成员数量、恒为 O(1)、Key 不存在返回 0、返回 0 即集合 Key 不存在、只读可安全高频调用、别用 SMEMBERS 取长度、与 LLEN/HLEN/ZCARD/XLEN 同属长度家族、精确计数对比 HyperLogLog 的近似基数、不要用"先 SCARD 再操作"做并发控制。