有一篇关于Redis命令以获取所有可用键的文章,但我想使用Python来完成。
有什么办法吗?
Answers:
使用 scan_iter()
scan_iter()
优于keys()
大量密钥,因为它为您提供了可以使用的迭代器,而不是尝试将所有密钥加载到内存中。
我的redis中有一个1B记录,而且我永远都无法获得足够的内存来一次返回所有密钥。
一对一扫描键
这是一个python代码段,scan_iter()
用于从商店中获取与某个模式匹配的所有键,并一一删除它们:
import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
for key in r.scan_iter("user:*"):
# delete the key
r.delete(key)
批量扫描
如果要扫描的键列表非常大(例如,大于100k的键),则分批扫描它们将更加高效,如下所示:
import redis
from itertools import izip_longest
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# iterate a list in batches of size n
def batcher(iterable, n):
args = [iter(iterable)] * n
return izip_longest(*args)
# in batches of 500 delete keys matching user:*
for keybatch in batcher(r.scan_iter('user:*'),500):
r.delete(*keybatch)
我对该脚本进行了基准测试,发现使用500个批处理的规模比一对一扫描密钥快5倍。我测试了不同的批次大小(3,50,500,1000,5000),发现500的批次大小似乎是最佳的。
请注意,无论您使用scan_iter()
orkeys()
方法,该操作都不是原子操作,并且可能会部分失败。
绝对避免在命令行上使用XARGS
我不建议在其他地方重复此示例。对于unicode键,它将失败,对于中等数量的键,它的速度也非常慢:
redis-cli --raw keys "user:*"| xargs redis-cli del
在此示例中,xargs为每个密钥创建一个新的redis-cli进程!那很糟。
我对这种方法进行了基准测试,它比第一个python示例慢4倍,在该示例中,它逐个删除每个键,并且比批量删除500个实例慢20倍。
是的,keys()
从StrictRedis模块使用:
>>> import redis
>>> r = redis.StrictRedis(host=YOUR_HOST, port=YOUR_PORT, db=YOUR_DB)
>>> r.keys()
提供空模式将获取所有这些模式。按照链接的页面:
键(模式='*')
返回匹配模式的键列表
SCAN
命令的引用,因为现在这是获取每个请求的O(1)时间复杂度的所有键的首选方法。(以及所有请求的O(N))
r.keys()
当您尝试匹配模式而不仅仅是返回所有键时,它相当慢。考虑scan
按照以下答案中的建议使用
我想添加一些示例代码与Patrick的答案以及其他代码一起使用。
这显示了使用键和scan_iter技术的结果。并且请注意,Python3使用zip_longest而不是izip_longest。下面的代码循环遍历所有键并显示它们。我将batchsize设置为变量12,以减小输出。
我写这篇文章是为了更好地理解密钥的批处理工作方式。
import redis
from itertools import zip_longest
\# connection/building of my redisObj omitted here
\# iterate a list in batches of size n
def batcher(iterable, n):
args = [iter(iterable)] * n
return zip_longest(*args)
result1 = redisObj.get("TestEN")
print(result1)
result2 = redisObj.get("TestES")
print(result2)
print("\n\nLoop through all keys:")
keys = redisObj.keys('*')
counter = 0
print("len(keys)=", len(keys))
for key in keys:
counter +=1
print (counter, "key=" +key, " value=" + redisObj.get(key))
print("\n\nLoop through all keys in batches (using itertools)")
\# in batches of 500 delete keys matching user:*
counter = 0
batch_counter = 0
print("Try scan_iter:")
for keybatch in batcher(redisObj.scan_iter('*'), 12):
batch_counter +=1
print(batch_counter, "keybatch=", keybatch)
for key in keybatch:
if key != None:
counter += 1
print(" ", counter, "key=" + key, " value=" + redisObj.get(key))
输出示例:
Loop through all keys:
len(keys)= 2
1 key=TestES value=Ola Mundo
2 key=TestEN value=Hello World
Loop through all keys in batches (using itertools)
Try scan_iter:
1 keybatch= ('TestES', 'TestEN', None, None, None, None, None, None, None, None, None, None)
1 key=TestES value=Ola Mundo
2 key=TestEN value=Hello World
请注意,redis命令是单线程的,因此执行keys()可能会阻止其他redis活动。请参阅此处的优秀文章,其中详细说明了这一点:Redis中的扫描与密钥性能