REDIS:获得所有哈希值的最佳方法



我当前在我的redis表中存储了约50k哈希,每个单个都有5个键/值对。每天一次,我运行一个批处理作业,以更新哈希值,包括将一些键值设置为哈希中的另一个键的值。

这是我的python代码,如果存在new_code value,则通过键迭代并将old_code设置为new_code:

pipe = r.pipeline()
for availability in availabilities:
    pipe.hget(availability["EventId"], "new_code")
for availability, old_code in zip(availabilities, pipe.execute()):
    if old_code:
        availability["old_code"] = old_code.decode("utf-8")
for availability in availabilities:
    if "old_code" in availability:
        pipe.hset(
            availability["EventId"], "old_code", availability["old_code"])
    pipe.hset(availability["EventId"], "new_code", availability["MsgCode"])
pipe.execute()

对我来说有点奇怪,我必须两次通过钥匙迭代以实现相同的结果,有没有更好的方法来做到这一点?

我要弄清楚的另一件事是如何以最佳性能获取所有哈希值。这是我目前这样做的方式:

d = []
pipe = r.pipeline()
keys = r.keys('*')
for key in keys:
    pipe.hgetall(key)
for val, key in zip(pipe.execute(), keys):
    e = {"event_id": key}
    e.update(val)
    if "old_key" not in e:
        e["old_key"] = None
    d.append(e)

因此,基本上我要做keys *,然后在所有键中用HGETALL迭代以获取值。这太慢了,尤其是迭代。有更快的方法吗?

undsed down变化怎么样。转换您存储数据的方式。

而不是具有5个值的50k哈希。具有50k值的 5哈希。

例如,您的哈希取决于Evend,您将new_code,old_code和其他东西存储在哈希

现在,对于new_code,有一个哈希地图,该映射将包含EventID作为成员,并且值为值。因此,单独的new_code是一个包含50k成员价值对的哈希地图。

因此,通过5而不是50k循环会相对较快。

我做了一些实验,以下是数字

50k hashes * 5 elements 
Memory : ~12.5 MB
Time to complete loop through of elements : ~1.8 seconds
5 hashes * 50k elements
Memory : ~35 MB
Time to complete loop through of elements : ~0.3 seconds.

我已经用简单的字符串(例如key_i and value_i(我是增量器))进行了测试,因此内存可能会增加。而且我刚刚浏览了数据,我没有进行任何操作,所以时间在您的情况下也会有所不同。

您可以看到此更改可以给您 5X绩效提升, 2倍的内存

redis对范围内的哈希进行压缩(512-默认值)。由于我们存储的范围超过了(50k),因此我们在内存中具有这种尖峰。

基本上,这是一种权衡,您可以选择适合您申请的最佳选择。

对于您的第一个问题:

  1. 您正在每个哈希中获得new_code的值,现在您有单个哈希中的所有内容 ->只有一个电话。
  2. 然后,您正在更新old_code和new_code。现在,您可以使用单个呼叫使用HMSET对其进行操作。

希望这会有所帮助。

对于您的第一个问题,使用LUA脚本肯定会提高性能。这是未经测试的,但类似:

update_hash = r.register_script("""
    local key = KEYS[1]
    local new_code = ARGS[1]
    local old_code = redis.call("HGET", key, "new_code")
    if old_code then
        redis.call("HMSET", key, "old_code", old_code, "new_code", new_code)
    else
        redis.call("HSET", key, "new_code", new_code)
    end
""")
# You can use transaction=False here if you don't need all the 
# hashes to be updated together as one atomic unit.
pipe = r.pipeline()
for availability in availabilities:
    keys = [availability["EventId"]]
    args = [availability["MsgCode"]]
    update_hash(keys=keys, args=args, client=pipe)
pipe.execute()

对于第二个问题,您可以通过编写简短的LUA脚本再次使其更快。您的脚本没有获取所有键并将其返回客户端,而是将其关联的键和数据返回,然后将其返回。

(不过请注意,无论您在哪里,调用keys()都会固有地慢。请注意,在任何一种方法中,您本质上都将整个REDIS数据集都拉到本地内存中,这可能会或可能不会成为问题。)

没有这样的命令,redis哈希在哈希中起作用,因此在一个哈希内部工作,并在该哈希中提供所有字段。无法在的多个哈希中访问所有字段。

有2个选项

  1. 使用管道
  2. 使用lua

但是,这两个都是解决方法,而不是解决问题的解决方案。要知道如何在此问题中检查我的答案:REDIS中是否有Hash数据结构类似的命令?

最新更新