【问题标题】:Efficient way to store 1:n records in Redis在 Redis 中存储 1:n 记录的有效方法
【发布时间】:2022-09-25 15:18:06
【问题描述】:

我以前没有使用 Redis 的经验,我正在编写一个简单的应用程序来更好地了解它。

在我的应用程序中,有一个player(和他的player_id)可以玩一个或多个game(每个都有它的game_id),我想保存玩家的start_datelast_played 信息。

我在 Redis 中创建了一个 registration 键作为哈希,我计划在其中添加几条 <player_id_game_id> 记录,其 JSON 值为

{
  \"start_date\": ...,
  \"last_played\": ...
}

但我很快遇到了一个问题,我无法通过 Redis 查询获取单个用户的所有游戏(类似于 HGET registration 10_* 获取所有玩家 10 的游戏)

然后我切换到玩家列表的游戏方法

{
  \"games\":[
    {
      \"start_date\": ...,
      \"last_played\": ...
    },
    {
      \"start_date\": ...,
      \"last_played\": ...
    }...
  ]
}

这样HGET registration 10 就会得到所有玩家 10 的游戏列表

然而,这伴随着每个更新操作需要我从 Redis 获取列表,修改它然后更新 Redis 中的记录的意识,并且我担心具有更大数据量和/或操作的性能。

这是一个好方法,还是有更好的方法?我不关心这个示例应用程序的具体实现(例如,将数据存储为 JSON 并不重要),而是针对类似情况的“正确”(或最佳)设计。
提前致谢。

标签: redis


【解决方案1】:

无论如何,该用例将有多个 redis 获取/更新。

拥有多个键来保存数据通常是最好的方法,因为您可以通过使用不同的数据类型(键、哈希、列表等)来优化数据获取/更新,以尽可能多地获取一些 0(1) 命令。

这里有一个名为player_id 的列表持有game_id 和名为game_id 的哈希值持有player_id:startplayer_id:end 接缝就像一个好主意,因为:

  1. 您可以通过命令LRANGE player_id 0 -1 获取玩家的所有游戏。它是 O(N)(与 HGETALL 相同),但如果您只想存储最后 10 场比赛,您可以使用 LPUSHRPOP(或 RPOPLPUSH )之类的命令来进行滚动队列

  2. 一旦您使用RPOP(或RPOPLPUSH )从player_id 列表中删除一个元素,您就可以使用HDEL 直接删除game_idplayer_id:startplayer_id:end 键,因为它不再需要了。只做 2 次获取/更新。

  3. 由于哈希属性,您可以轻松知道玩家是否以 0(1) 方式参与游戏。

    这个解决方案的问题是你不能轻易找到一个游戏的所有玩家,唯一的方法是HGETALL 但它是 O(N) 并且你不需要它会给你的一半数据。我认为您可以将此哈希分成两部分:game_id:startgame_id:end,每个都包含相应的 player_id 数据。这种数据结构没有真正的权衡,因为读/写的数量是相同的,您只需优化游戏中所有玩家的检索。

    PS:存储字符串化的 JSON 几乎从来都不是一个好主意,因为您无法利用 redis 的强大功能。如果你真的想要,你可以使用 RedisJSON 来两全其美。

【讨论】:

  • 这确实很有用,但是由于需要为每个玩家提供单独的数据(例如,两个玩家在同一个游戏中会有不同的值),然后我需要为不能单独作为 game_id 的哈希生成一个新的 id,还是我错过了什么?至于 JSON,我很欣赏这个建议,但这只是一个例子,对问题本身并不重要
  • @GrfPT4 答案已更新,我猜我不明白您的问题 =) PS:我知道您没有就 JSON 部分征求意见,但我不得不说,我认为以非最佳方式做事不是一个好主意即使是锻炼自己,我会说相反!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-13
  • 1970-01-01
  • 2018-10-18
相关资源
最近更新 更多