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

128 投票
6 回答
174079 浏览
提问于 2025-04-17 21:19

有一篇帖子讲了一个Redis命令,可以用来获取所有可用的键,但我想用Python来实现这个功能。

有没有什么方法可以做到这一点呢?

6 个回答

2

在上面接受的答案基础上,补充一点。

scan_iter可以和一个叫count的参数一起使用,这样可以让redis在一次操作中搜索多个键。这可以大大加快获取键的速度,特别是当你使用匹配模式并且在大量键的情况下。

不过,要小心使用过高的count值,因为这可能会影响其他同时进行的查询的性能。

https://docs.keydb.dev/blog/2020/08/10/blog-post/ 这里有一篇文章,里面有更多细节和一些性能测试的数据。

3

我想给Patrick的回答和其他人的回答加一些示例代码。
这个示例展示了使用键和scan_iter技术的结果。请注意,Python3使用的是zip_longest,而不是izip_longest。下面的代码会遍历所有的键并显示出来。我把批处理大小设置为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与KEYS在Redis中的性能比较

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

使用 Pyredis 库

scan 命令

自 2.8.0 版本起可用。

时间复杂度:每次调用的复杂度是 O(1)。完整迭代的复杂度是 O(N),这包括足够的命令调用,直到光标返回到 0。N 是集合中元素的数量。

80

没错,可以使用keys()这个方法,它来自StrictRedis模块:

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

如果你给它一个空的模式,它会把所有的键都取出来。根据链接中的说明:

keys(pattern='*')

这个方法会返回一个符合模式的键的列表

186

使用 scan_iter()

scan_iter()keys() 更适合处理大量键,因为它提供了一个迭代器,你可以逐个处理,而不是试图一次性把所有键都加载到内存中。

我在我的 Redis 数据库里有10亿条记录,根本无法找到足够的内存一次性返回所有的键。

逐个扫描键

下面是一个使用 scan_iter() 的 Python 代码片段,它可以从存储中获取所有匹配某个模式的键,并逐个删除:

import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
for key in r.scan_iter("user:*"):
    # delete the key
    r.delete(key)

批量扫描

如果你要扫描的键的数量非常大,比如超过10万个,分批扫描会更有效率,像这样:

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

撰写回答