使用python获取Redis数据库中的所有键


76

有一篇关于Redis命令以获取所有可用键的文章,但我想使用Python来完成。

有什么办法吗?

Answers:


112

使用 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倍。


在r.scan_iter()上进行迭代时,我不断收到“ redis.exceptions.ResponseError:未知命令'SCAN'”。知道为什么吗?我还没有找到答案。
BringBackCommodore64 '17

1
@ BringBackCommodore64您的Redis版本太旧,请安装新版本。
piokuc

@piokuc好吧,我还没有升级我的Redis,但是您的猜测似乎很正确!
BringBackCommodore64

@ BringBackCommodore64这不是一个猜测。我有同样的问题,升级解决了。我不记得我所拥有的不支持SCAN的版本,但是它已经使用了几年。Redis的任何最新版本都可以。
piokuc

1
@LeiYang redis搜索允许使用通配符/通配符。因此,“ mykey *” ,“ user _,“ user: ”。redis.io/commands/keys
Patrick Collins

57

是的,keys()从StrictRedis模块使用:

>>> import redis
>>> r = redis.StrictRedis(host=YOUR_HOST, port=YOUR_PORT, db=YOUR_DB)
>>> r.keys()

提供空模式将获取所有这些模式。按照链接的页面:

键(模式='*')

返回匹配模式的键列表


14
请注意,不建议在生产服务器上使用此命令。如果密钥数量很多,则Redis实例在处理该请求时将不会响应任何其他请求,这可能需要很长时间才能完成。
Pascal Le Merrer 2014年

2
考虑添加对SCAN命令的引用,因为现在这是获取每个请求的O(1)时间复杂度的所有键的首选方法。(以及所有请求的O(N))
Kirill Zaitsev 2014年

2
r.keys()当您尝试匹配模式而不仅仅是返回所有键时,它相当慢。考虑scan按照以下答案中的建议使用
cnicolaou

2
@KonstantineNikolaou我通知了OP,他很高兴地拒绝接受我的回答。感谢您的举报,我很久以前就使用过此功能,但现在我没有专注于该主题以检查最佳效果。
fedorqui'SO停止伤害

@fedorqui高兴地听到,😊
cnicolaou

11
import redis
r = redis.Redis("localhost", 6379)
for key in r.scan_iter():
       print key

使用Pyredis库

扫描命令

自2.8.0起可用。

时间复杂度:每次通话O(1)。O(N)表示完整的迭代,包括足以使游标返回到0的命令调用。N是集合内元素的数量。


0

我想添加一些示例代码与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中的扫描与密钥性能

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.