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

时间:2014-03-07 16:34:19

标签: python database redis

有一篇关于Redis命令的帖子来获取所有可用的密钥,但我想用Python来做。

有什么办法吗?

5 个答案:

答案 0 :(得分:74)

对于大量的键,

scan()优于keys(),因为它为您提供了一个可以使用的迭代器,而不是尝试将所有键加载到内存中。

我的redis中有一条1B记录,我无法获得足够的内存来立即返回所有密钥。

逐个扫描

这是一个python代码段,使用scan()从商店获取与模式匹配的所有密钥并逐个删除它们:

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倍。批量大小为500似乎是我Macbook Pro本地运行的最佳选择,它可能因网络而异。我测试了10,100,500,1000和10000的批量大小。如果您想看看我如何对其进行基准测试,请与我联系。

请注意,无论您使用scan()还是keys()方法,操作都不是原子操作,可能会在某个时间内失败。

在命令行中使用XARGS绝对避免

我不建议我在其他地方重复发现这个例子。它不适用于unicode键,即使是中等数量的键也非常慢:

redis-cli --raw keys "user:*"| xargs redis-cli del

在这个例子中,xargs为每个键创建一个新的redis-cli进程!亚克西。

我对这种方法进行了基准测试,比第一个python示例慢了4倍,在这个示例中,它逐个删除每个键,比以500个批量删除的速度慢20倍。

答案 1 :(得分:37)

是的,请使用StrictRedis模块中的keys()

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

给出一个空模式将获取所有这些模式。根据页面链接:

  

键(图案= '*')

     

返回匹配模式

的键列表

答案 2 :(得分:8)

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是集合中元素的数量..

答案 3 :(得分:1)

对上述已接受答案的补充。

scan_iter 可以与 count 参数一起使用,以便告诉 redis 在单次迭代期间搜索多个键。这可以显着加快键的获取速度,尤其是在与匹配模式和大键空间一起使用时。

对计数使用非常高的值时要小心谨慎,因为这可能会破坏其他并发查询的性能。

https://docs.keydb.dev/blog/2020/08/10/blog-post/ 这是一篇包含更多详细信息和一些基准测试的文章。

答案 4 :(得分: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活动。请参见此处的精彩文章,其中更详细地说明了这一点:SCAN vs KEYS performance in Redis

相关问题