让我们将 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 功能。