迭代redis db

时间:2018-05-23 10:54:03

标签: python redis redis-py

我有一个拥有大约350,000个密钥的数据库。目前我的代码只是循环遍历所有键并从db获取其值。

然而,这需要将近2分钟,这似乎非常缓慢,redis-benchmark给出了100k reqs / 3s。

我看过流水线操作,但我需要返回每个值,这样我最终会得到一个键值对的字典。

目前我正在考虑在我的代码中使用线程,如果可能的话加快速度,这是处理这个用例的最好方法吗?

这是我到目前为止的代码。

import redis, timeit
start_time = timeit.default_timer()
count = redis.Redis(host='127.0.0.1', port=6379, db=9)
keys = count.keys()

data = {}

for key in keys:
    value = count.get(key)
    if value:
        data[key.decode('utf-8')] = int(value.decode('utf-8'))

elapsed = timeit.default_timer() - start_time

print('Time to read {} records: '.format(len(keys)), elapsed)

2 个答案:

答案 0 :(得分:2)

首先,最快的方法是在EVAL内完成所有这些工作。

接下来,迭代所有密钥的推荐方法是SCAN。它不会比KEYS更快地迭代,但会允许Redis处理其中的一些其他操作,因此它将有助于整体应用程序行为。

脚本将类似于local data={} local i=1 local mykeys=redis.call(\"KEYS\",\"*\") for k=1,#mykeys do local tmpkey=mykeys[k] data[i]={tmpkey,redis.call(\"GET\",tmpkey)} i=i+1 end return data,但如果GET(如集合,列表)无法访问密钥,则会失败。您需要为其添加错误处理。如果需要排序,可以直接在LUA中执行,也可以稍后在客户端执行。第二个会慢一点,但不会让redis实例的其他用户等待。

示例输出:

127.0.0.1:6370> eval "local data={} local i=1 local mykeys=redis.call(\"KEYS\",\"*\") for k=1,#mykeys do local tmpkey=mykeys[k] data[i]={tmpkey,redis.call(\"GET\",tmpkey)} i=i+1 end return data" 0
1) 1) "a"
   2) "aval"
2) 1) "b"
   2) "bval"
3) 1) "c"
   2) "cval"
4) 1) "d"
   2) "dval"
5) 1) "e"
   2) "eval"
6) 1) "f"
   2) "fval"
7) 1) "g"
   2) "gval"
8) 1) "h"
   2) "hval"

答案 1 :(得分:2)

我遇到了同样的问题,最终使用KEYSMGET来同时迭代多个键:

import redis
url='redis://my.redis.url'
query='product:*'

client = redis.StrictRedis.from_url(url, decode_responses=True)
keys = client.keys(query)

def chunks(lst, n):
    for i in range(0, len(lst), n):
        yield lst[i:i + n]

partitions = list(chunks(keys, 10000))

data = []
for keys in partitions:
    values = client.mget(keys)
    data.extend(zip(keys, values))

print(len(data))

I've written a blog on showing progress while writing the result to a file

此代码是redis-mass-get Python package的基础。可以这样做,就像这样:

from redis_mass_get import RedisQuery

# pluralize will return the result or None
q = RedisQuery("redis://my.amazing.redis.url")

# query data 
data = q.query("product:*")
# data is returned as:
# [(key1, value1), (key2, value2)]