不能。redis lua脚本中必须通过redis.call("sunion", key1, key2)调用,不可直接执行命令字符串;返回空结果常见于键不存在或为空集,且需用unpack()展开结果才能传给sadd。

Redis Lua脚本里能直接用 SUNION 吗?
不能。Lua 脚本运行在 Redis 服务端,但不支持直接调用 Redis 命令字符串(比如 "SUNION key1 key2")。必须通过 redis.call() 或 redis.pcall() 显式发起命令调用,且参数要拆成独立字符串传入。
redis.call("SUNION", key1, key2, key3) 为什么返回空结果?
常见原因是键不存在或为空集合:SUNION 对不存在的 key 视为空集,结果仍是空;但如果所有输入 key 都不存在,返回的就是空数组(Lua 中为 {}),容易被误判为“没执行成功”。另外注意:key 必须是字符串类型,若混入 hash / zset 会报错 WRONGTYPE Operation against a key holding the wrong kind of value。
- 务必先用
redis.call("EXISTS", key)或redis.call("TYPE", key)校验键存在性和类型 - 避免硬编码 key 名,应通过
KEYS[1],KEYS[2]等传入,保证沙箱安全 - 如果想兼容空 key,可提前用
if #res == 0 then ... end处理返回值
合并多个 SET 并写回新 key 的完整写法
典型场景是把若干临时集合归并到一个持久化结果集。关键点在于:不能对 redis.call("SUNION", ...) 的返回值直接 SADD —— 它返回的是 table(Lua 数组),而 SADD 要求逐个元素作为参数传入。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
local keys = KEYS
local dest = keys[1]
table.remove(keys, 1) -- 第一个 KEY 是目标 key,其余是源 SET
<p>local union_res = redis.call("SUNION", unpack(keys))
if #union_res == 0 then
redis.call("DEL", dest) -- 清空目标,避免残留
else
redis.call("SADD", dest, unpack(union_res)) -- 注意 unpack!
end
return #union_res</p>
⚠️ 注意:unpack() 在 Redis 7.0+ 内置 Lua 5.1 环境中可用;若用旧版 Redis(如 6.x),需手动展开,例如 redis.call("SADD", dest, union_res[1], union_res[2], ...),但长度受限(Redis 命令参数上限通常为 1024)。
性能和原子性边界在哪?
SUNION 在 Lua 中执行仍是原子的,但代价是:它会把所有源集合的全部成员加载进内存再去重。若单个 SET 有 10 万成员、共 5 个 key,脚本内就要处理 50 万字符串对象 —— 可能触发 Lua 内存限制(lua-time-limit)或拖慢整个 Redis 实例。
- 大集合合并优先考虑客户端分批 +
SUNIONSTORE,而非 Lua - 若必须用 Lua,建议加
redis.call("SCARD", key) 做前置检查,超限则 abort 并返回错误 - 不要在
SUNION结果上再套SRANDMEMBER或SMEMBERS—— 这会让内存占用翻倍
真正难的不是语法,而是判断“该不该在 Lua 里做这件事”——数据量、超时风险、是否真需要原子性,这几个条件漏掉任何一个,都可能让脚本从优化变成瓶颈。










