Redis命令:SCARD

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 再操作"做并发控制。

相关推荐
OxYGC2 小时前
[工程] Redis 配置文件redis.conf全解析
数据库·redis·bootstrap
码士集团小青11 小时前
SpringBoot 集成缓存性能之王 Caffeine
spring boot·后端·缓存
SHENGWEI胜为15 小时前
交换机端口显示正常,终端却获取不到 IP 地址?从 DHCP 流程定位故障
服务器·网络·测试工具·缓存·通信工程
夕除18 小时前
redis--数据类型 string list
redis
一条泥憨鱼18 小时前
【Redis | 黑马点评】分布式锁;Lua脚本;Redisson与看门狗 |源码万字详解
redis·分布式·lua
stark张宇19 小时前
库存扣减的“锁”事:悲观锁、乐观锁、分布式锁
redis·分布式·mysql
AAASilverwolf20 小时前
OpenAI 新增 12 小时提示缓存:跨小时任务能省多少?
人工智能·gpt·缓存·api
Sayuanni%31 天前
Redis(初阶)
数据库·redis·缓存
未秃头的程序猿1 天前
一次重复扣款的复盘:分布式锁加错了维度,比不加锁更危险
java·redis·后端