假设有数百万个键,格式为prefix:<numeric_id>
。
我想要原子地删除它们所有。
如何使用Redis原子方式删除匹配模式的键展示了很多选项。一些使用redis-cli
或Bash脚本,但我需要在我的客户端程序中进行操作。
使用Lua脚本的方法很有前途,但是使用KEYS
命令的解决方案会失败并显示“元素过多无法打包”的错误信息。
该如何解决这个问题?
假设有数百万个键,格式为prefix:<numeric_id>
。
我想要原子地删除它们所有。
如何使用Redis原子方式删除匹配模式的键展示了很多选项。一些使用redis-cli
或Bash脚本,但我需要在我的客户端程序中进行操作。
使用Lua脚本的方法很有前途,但是使用KEYS
命令的解决方案会失败并显示“元素过多无法打包”的错误信息。
该如何解决这个问题?
SCAN
命令,在脚本内以块为单位进行删除,避免了“too many elements to unpack”错误。local cursor = 0
local calls = 0
local dels = 0
repeat
local result = redis.call('SCAN', cursor, 'MATCH', ARGV[1])
calls = calls + 1
for _,key in ipairs(result[2]) do
redis.call('DEL', key)
dels = dels + 1
end
cursor = tonumber(result[1])
until cursor == 0
return "Calls " .. calls .. " Dels " .. dels
它会返回 SCAN
被调用的次数和删除的键数。
用法:
EVAL "local cursor = 0 local calls = 0 local dels = 0 repeat local result = redis.call('SCAN', cursor, 'MATCH', ARGV[1]) calls = calls + 1 for _,key in ipairs(result[2]) do redis.call('DEL', key) dels = dels + 1 end cursor = tonumber(result[1]) until cursor == 0 return 'Calls ' .. calls .. ' Dels ' .. dels" 0 prefix:1
注意,运行此命令时将会阻塞服务器,因此建议不要在生产环境中使用。
对于生产环境,请考虑将 DEL
更改为 UNLINK
。您还可以返回游标(而不是在脚本内重复,直到游标为零),并向 SCAN 添加 COUNT 参数以进行限制(详见 REDIS 中 SCAN/HSCAN 命令的 COUNT 推荐值是多少?)。这样可以分批处理而不是一次性处理所有数据,类似于 如何获取 Redis 中所有集合的数据?
或者,您可以采用本回答中提到的更为复杂的方法:Redis `SCAN`:如何在新的可能匹配的键和保证合理时间内的最终结果之间保持平衡?
SCAN
,看看是否有任何键与其匹配。 - LeoMurilloERR Error running script: @user_script:1: ERR invalid cursor stack traceback: [G]: in function 'call' @user_script:1: in main chunk [G]: ?
的错误信息。 - ehrencrona