【问题标题】:How to design Redis data structures in order to perform queries similar to DB queries in redis?如何设计 Redis 数据结构以便在 redis 中执行类似于 DB 查询的查询?
【发布时间】:2017-04-06 18:20:21
【问题描述】:

我有 Job、JobInfo 等表。我想执行如下查询 -

“从 Job J、JobInfo B 中选择 J.JobID,其中 B.JobID = J.JobID AND BatchID=5850 AND B.Status=0 AND J.JobType2”

我应该如何编写我的 redis 数据类型,以便我可以在 redis 中映射此类查询?

如果我尝试将表作业的行映射到 redis 哈希中,例如(hash j jobid 1 status 2) & 类似地,表 JobInfo 的行再次在 redis 哈希中作为 (hash jinfo jobid 1 jobtype 3.)

所以我的表可以是一组哈希值。作业表可以设置条目 JobSet:jobid & JobInfo 表可以设置条目如 JobInfoSet:jobid

但我对什么时候在 JobSet 和 JobInfoSet 上进行 SINTER 感到困惑。我将如何查询该哈希以获取密钥?由于set jobSet 的hash 内容与表JobInfoSet 的hash 内容不完全相同(它们可能有不同的键值对。

那么作为 SINTER 的输出,我究竟会得到什么?我将如何将该输出查询为键值对?

所以这些表将是 redis 哈希的集合

【问题讨论】:

    标签: sql redis


    【解决方案1】:

    Redis 并非旨在以 SQL 方式构造数据。除了内存中的键值存储之外,它还支持五种类型的数据结构:字符串、哈希、列表、集合和排序集。在高层次上,这足以暗示 Redis 旨在解决由于关系数据模型中的高计算量而出现的性能问题。但是,如果您想在内存结构中执行 sql 查询,您可能需要查看memsql

    【讨论】:

      【解决方案2】:

      让我们将 SQL 语句分解成不同的组件,我将尝试展示 redis 是如何完成各个部分的。

      从Job J中选择J.JobID、J.JobName;

      我们使用 SQL 主索引作为 redis 中的 redis 自然索引,将“Job”中的每一行翻译成 redis 中的哈希。 例如: SQL

      ==JobId==|==Name==
      123        Fred
      

      Redis HSET 作业:123 姓名 Fred 可以概念化为

      Job-123 => {"Name":"Fred"}
      

      因此我们可以将列作为哈希字段存储在 redis 中

      假设我们对 JobInfo 做同样的事情。每个 JobInfo 对象都有自己的 ID

      JobInfo-876 => {"meta1": "some value", "meta2": "bla", "JobID": "123"}
      

      在 sql 中,我们通常会在 JobInfo.JobID 上创建二级索引,但在 NoSql 领域,我们会维护自己的二级索引。

      Sorted Sets 非常适合这个。 因此,当我们想通过某个字段获取 JobInfo 对象时,在这种情况下,JobId 我们可以将它添加到这样的排序集中 ZADD JobInfo-JobID 123 JobInfo-876

      这导致其中包含 1 个元素的集合 {JobInfo-876} 得分为 123。我意识到强制所有 JobID 进入分数的浮动范围是一个坏主意,但请在这里与我合作。

      现在,当我们要查找给定 JobID 的所有 JobInfo 对象时,我们只需对索引进行 log(N) 查找。 ZRANGEBYSCORE JobInfo-JobID 123 123 返回“JobInfo-876”

      现在要实现简单的连接,我们只需通过按 JobID 存储 Job 键来重用此 JobInfo-JobID 索引。 ZADD JobInfo-JobID 123 Job-123

      因此,当做类似的事情时 SELECT J.JobID, J.Name, B.meta1 FROM Job, JobInfo USING (JobID)。

      这将转化为扫描 JobInfo-JobID 二级索引并重新组织返回的 Job 和 JobInfo 对象。 ZRANGEBYSCORE JobInfo-JobID -inf +inf WITHSCORES 5 -> (Job-123, JobInfo-876)

      这些对象都共享同一个 JobID。客户端然后您将异步获取所需的字段。或者您可以将这些查找嵌入到 lua 脚本中。这个 lua 脚本可能会让 redis 长时间挂起。通常,redis 会尝试对客户公平,并希望您使用短批次查询而不是一个长查询。

      现在我们遇到一个大问题,如果我们想合并二级索引怎么办。假设我们在 JobInfo.Status 上有一个二级索引,在 Job.JobType 上有另一个。 如果我们使用正确的 JobType 制作一组所有作业并将其用作 JobInfo-JobID 共享二级索引上的过滤器,那么我们不仅消除了错误的 Job 元素,而且还消除了每个 JobInfo 元素。我们可以,我猜想获取交叉点上的分数(JobID)并重新获取具有这些分数的所有 JobInfo 对象,但是我们丢失了一些我们所做的过滤。

      redis 就在这个时候崩溃了。

      这里是redis的创建者自己写的关于二级索引的文章:http://redis.io/topics/indexes 他触及多维索引以进行过滤。如您所见,他以一种非常通用的方式设计了数据结构。最吸引人的一点是具有相同分数的已排序集合元素按字典顺序存储。因此,您可以轻松地让所有元素得分为 0,并搭载 Redis 的速度,并像 cockroachDB 一样使用它,它依赖于全局顺序来实现许多 SQL 功能。

      【讨论】:

      • 更正:ZRANGEBYSCORE JobInfo-JobID -inf +inf WITHSCORES 5 -> (Job-123, JobInfo-876)
      • 更正:ZRANGEBYSCORE JobInfo-JobID -inf +inf WITHSCORES 123 -> (Job-123, JobInfo-876)
      【解决方案3】:

      对于 3.4 及以下版本的 redis,其他答案完全正确

      从 4.0 开始的最新版本的 redis 包括对模块的支持。

      模块非常强大,碰巧我刚刚写了一个小模块来将 SQLite 嵌入到 redis 本身中; rediSQL.

      使用该模块,您实际上可以在您的 redis 实例中使用功能齐全的 SQL 数据库。

      【讨论】:

        猜你喜欢
        • 2021-11-08
        • 2021-10-13
        • 2016-04-29
        • 2021-10-02
        • 1970-01-01
        • 1970-01-01
        • 2014-02-17
        • 2020-04-22
        • 1970-01-01
        相关资源
        最近更新 更多