使用python获取Redis数据库中的所有键
Posted
技术标签:
【中文标题】使用python获取Redis数据库中的所有键【英文标题】:Get all keys in Redis database with python 【发布时间】:2014-04-10 22:11:52 【问题描述】:有一篇关于获取所有可用密钥的 Redis 命令的帖子,但我想用 Python 来做。
有什么办法吗?
【问题讨论】:
【参考方案1】:使用scan_iter()
scan_iter()
在处理大量键时优于 keys()
,因为它为您提供了一个可以使用的迭代器,而不是尝试将所有键加载到内存中。
我的 redis 中有 1B 条记录,我永远无法获得足够的内存来一次返回所有键。
逐个扫描键
这是一个 python sn-p 使用 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()
还是keys()
方法,操作都不是原子操作,可能会在中途失败。
绝对避免在命令行中使用 XARGS
我不推荐这个我在其他地方发现重复的例子。对于 unicode 键,它会失败,即使是中等数量的键也会非常慢:
redis-cli --raw keys "user:*"| xargs redis-cli del
在这个例子中,xargs 为每个键创建一个新的 redis-cli 进程!这很糟糕。
我对这种方法进行了基准测试,它比第一个逐个删除每个键的 python 示例慢 4 倍,比批量删除 500 个键慢 20 倍。
【讨论】:
在迭代 r.scan_iter() 时,我不断收到“redis.exceptions.ResponseError: unknown command 'SCAN'”。知道为什么吗?我还没有找到答案。 @BringBackCommodore64 你的redis版本太旧,安装新的吧。 @piokuc 好吧,我还没有升级我的 redis,但你的猜测显然是对的! @LeiYang redis 搜索允许使用 glob/通配符。所以“mykey*”、“user_”、“user:”。 redis.io/commands/keys izip_longest 在 Python 3 中被重命名为 zip_longest ***.com/questions/38634810/…【参考方案2】:是的,使用 StrictRedis 模块中的keys()
:
>>> import redis
>>> r = redis.StrictRedis(host=YOUR_HOST, port=YOUR_PORT, db=YOUR_DB)
>>> r.keys()
给出一个空模式将获取所有这些。根据链接的页面:
键(模式='*')
返回匹配模式的键列表
【讨论】:
请注意,不鼓励在生产服务器上使用此命令。如果您有大量密钥,您的 Redis 实例在处理此请求时将不会响应任何其他请求,这可能需要相当长的时间才能完成。 考虑添加对SCAN
命令的引用,因为它现在是获取每个请求的 O(1) 时间复杂度的所有键的首选方法。 (以及所有请求的 O(N))
r.keys()
在您尝试匹配模式而不只是返回所有键时非常慢。考虑使用scan
,如下面答案中的建议
@KonstantineNikolaou 我通知了 OP,他很高兴不接受我接受另一个答案的答案。感谢您的报告,我很久以前就使用过这个,但我现在缺乏对主题的关注来检查什么是最好的。
@SoroushParsa 如果您支持scan()
选项,则支持另一个答案。事实上,我的是被接受的,我要求 OP 接受另一个。对我来说,否决这个本身并不符合“这个答案没用”的事情。【参考方案3】:
import redis
r = redis.Redis("localhost", 6379)
for key in r.scan_iter():
print key
使用 Pyredis 库
scan command
自 2.8.0 起可用。
时间复杂度:每次调用 O(1)。 O(N) 用于完整的迭代,包括足够的命令调用以使光标返回 0。N 是集合内的元素数..
【讨论】:
【参考方案4】:对上述已接受答案的补充。
scan_iter
可以与count
参数一起使用,以告诉redis 在单次迭代期间搜索多个键。这可以显着加快键的获取速度,尤其是在与匹配模式和大键空间一起使用时。
使用非常高的计数值时要小心,因为这可能会破坏其他并发查询的性能。
https://docs.keydb.dev/blog/2020/08/10/blog-post/ 这是一篇包含更多细节和一些基准的文章。
【讨论】:
【参考方案5】:我想添加一些示例代码以配合 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 comamnds 是单线程的,所以执行 keys() 可以阻止其他 redis 活动。在这里查看优秀的帖子,更详细地解释这一点:SCAN vs KEYS performance in Redis
【讨论】:
以上是关于使用python获取Redis数据库中的所有键的主要内容,如果未能解决你的问题,请参考以下文章