使用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数据库中的所有键的主要内容,如果未能解决你的问题,请参考以下文章

redis 全局命令 查看所有的键,删除键,检查键是否存在,获取过期时间,键的数据结构类型

如何获取redis内的所有内容

如何在javascript中获取redis中的所有键和值?

检索/列出 Redis 数据库中的所有键/值对

Redis中的数据类型及其基本使用

Redis中的数据类型及其基本使用