所以在使用scan命令的时候,如果需要迭代的遍历,需要每次调用都需要使用上一次这个调用返回的游标作为该次调用的游标参数,以此来延续之前的迭代过程。
至此,心中的疑惑就此解开,改了一版lua:
local c = tonumber(ARGV[1]) local resp = redis.call('SCAN',c,'MATCH','authToken*','COUNT',10000) c = tonumber(resp[1]) local dataList = resp[2] for i=1,#dataList do local d = dataList[i] local ttl = redis.call('TTL',d) if ttl == -1 then redis.call('DEL',d) end end return c在本地上传后执行:
可以看到,scan命令没法完全保证每次筛选的数量完全等同于给定的count,但是整个迭代却很好的延续下去了。最后也得到了游标返回0,也就是到了末尾。至此,测试数据20w被全部删完。
这段lua只要在套上shell进行循环就可以直接在生产上跑了。经过估算大概在12分钟左右能删除掉500w的数据。
知其然,知其所以然。虽然scan命令以前也曾玩过。但是的确不知道其中的细节。况且文档的翻译也不是那么的准确,以至于自己在面对错误的结果时整整浪费了近1个多小时的时间。记录下来,加深理解。
4.联系作者微信关注 「jishuyuanren」或者扫描以下二维码获取更多干货