扫描时获取 Redis 值
Get Redis values while scanning
我用这种方式创建了一个 Redis 键/值索引:
set 7:12:321 '{"some:"JSON"}'
键以冒号分隔,键的每一部分代表一个层次索引。
get 7:12:321
表示我知道确切的层次结构并且只想要一个项目
scan 7:12:*
表示我想要层次结构第一层中 id 7 和第二层结构中 id 12 下的每个项目。
问题是:如果我想要 JSON 值,我必须首先 scan
(几毫秒内约 50000 个条目)然后 get
每个键返回扫描一个一(800 毫秒)。
这不是很有效。这是我在 Whosebug 搜索 "scanning Redis values".
上找到的唯一答案
1/ 是否有另一种扫描 Redis 以获取值或键/值对而不仅仅是键的方法?我尝试 hscan
如下:
hset myindex 7:12:321 '{"some:"JSON"}'
hscan myindex MATCH 7:12:*
但它破坏了性能(50000 个条目将近 4s)
2/ Redis 中是否有我可以以相同方式使用但可以 "scan for values" (hset
?)
的另一种数据结构
3/ 我是否应该使用另一种数据存储解决方案(例如 PostgreSQL ltree
?)来满足我的高性能用例?
我一定漏掉了一些非常明显的东西,因为这听起来像是一个常见的用例。
感谢您的回答。
你可以考虑使用 Sorted Set 和字典范围,只要你只需要执行前缀搜索。有关此内容和一般索引的更多信息,请参阅 http://redis.io/topics/indexes
更新了示例:
考虑以下 -
$ redis-cli
127.0.0.1:6379> ZADD anotherindex 0 '7:12:321:{"some:"JSON"}'
(integer) 1
127.0.0.1:6379> ZRANGEBYLEX anotherindex [7:12: [7:12:\xff
1) "7:12:321:{\"some:\"JSON\"}"
现在去阅读这篇文章,以便您 1) 了解它的作用和 2) 知道如何避免可能的陷阱:)
Optimization for your current solution
而不是 get
逐一计算 scan
返回的每个键,您应该使用 mget
批量获取键值对,或使用 pipeline
减少 RTT。
Efficiency problem of your current solution
scan
命令迭代数据库中的所有键,即使与模式匹配的键数量很少。当按键数量增加时,性能会降低。
Another solution
由于层次索引是一个整数,您可以将层次索引编码成一个数字,并将该数字作为排序集的分数。这样,您可以按分数范围搜索,而不是按模式搜索,这对于排序集来说非常快。以下面为例
比如说,第一个(最右边)的层次索引小于1000,第二个索引小于100,那么你可以将索引(例如7:12:321
)编码成一个分数(321 + 12 * 1000 + 7 * 100 * 1000 = 712321)。然后将分数和值设置为排序集合:zadd myindex 712321 '{"some:"JSON"}'
.
当你想搜索匹配7:12:*
的键时,只需使用zrangebyscore
命令获取得分在712000和712999之间的数据:zrangebyscore myindex 712000 712999 withscores
.
这样就可以得到key(用返回的分数解码)和value了。它也应该比 scan
解决方案更快。
更新
解决方案有个小问题:sorted set 的成员必须是唯一的,所以你不能有 2 个具有相同值的键(即 json 字符串)。
// insert OK
zadd myindex 712321 '{"the_same":"JSON"}'
// failed to insert, members should be unique
zadd myindex 712322 '{"the_same":"JSON"}'
为了解决这个问题,可以将key和json字符串结合起来,使其唯一:
zadd myindex 712321 '7:12:321-{"the_same":"JSON"}'
zadd myindex 712321 '7:12:322-{"the_same":"JSON"}'
我用这种方式创建了一个 Redis 键/值索引:
set 7:12:321 '{"some:"JSON"}'
键以冒号分隔,键的每一部分代表一个层次索引。
get 7:12:321
表示我知道确切的层次结构并且只想要一个项目
scan 7:12:*
表示我想要层次结构第一层中 id 7 和第二层结构中 id 12 下的每个项目。
问题是:如果我想要 JSON 值,我必须首先 scan
(几毫秒内约 50000 个条目)然后 get
每个键返回扫描一个一(800 毫秒)。
这不是很有效。这是我在 Whosebug 搜索 "scanning Redis values".
上找到的唯一答案1/ 是否有另一种扫描 Redis 以获取值或键/值对而不仅仅是键的方法?我尝试 hscan
如下:
hset myindex 7:12:321 '{"some:"JSON"}'
hscan myindex MATCH 7:12:*
但它破坏了性能(50000 个条目将近 4s)
2/ Redis 中是否有我可以以相同方式使用但可以 "scan for values" (hset
?)
3/ 我是否应该使用另一种数据存储解决方案(例如 PostgreSQL ltree
?)来满足我的高性能用例?
我一定漏掉了一些非常明显的东西,因为这听起来像是一个常见的用例。
感谢您的回答。
你可以考虑使用 Sorted Set 和字典范围,只要你只需要执行前缀搜索。有关此内容和一般索引的更多信息,请参阅 http://redis.io/topics/indexes
更新了示例:
考虑以下 -
$ redis-cli
127.0.0.1:6379> ZADD anotherindex 0 '7:12:321:{"some:"JSON"}'
(integer) 1
127.0.0.1:6379> ZRANGEBYLEX anotherindex [7:12: [7:12:\xff
1) "7:12:321:{\"some:\"JSON\"}"
现在去阅读这篇文章,以便您 1) 了解它的作用和 2) 知道如何避免可能的陷阱:)
Optimization for your current solution
而不是 get
逐一计算 scan
返回的每个键,您应该使用 mget
批量获取键值对,或使用 pipeline
减少 RTT。
Efficiency problem of your current solution
scan
命令迭代数据库中的所有键,即使与模式匹配的键数量很少。当按键数量增加时,性能会降低。
Another solution
由于层次索引是一个整数,您可以将层次索引编码成一个数字,并将该数字作为排序集的分数。这样,您可以按分数范围搜索,而不是按模式搜索,这对于排序集来说非常快。以下面为例
比如说,第一个(最右边)的层次索引小于1000,第二个索引小于100,那么你可以将索引(例如7:12:321
)编码成一个分数(321 + 12 * 1000 + 7 * 100 * 1000 = 712321)。然后将分数和值设置为排序集合:zadd myindex 712321 '{"some:"JSON"}'
.
当你想搜索匹配7:12:*
的键时,只需使用zrangebyscore
命令获取得分在712000和712999之间的数据:zrangebyscore myindex 712000 712999 withscores
.
这样就可以得到key(用返回的分数解码)和value了。它也应该比 scan
解决方案更快。
更新
解决方案有个小问题:sorted set 的成员必须是唯一的,所以你不能有 2 个具有相同值的键(即 json 字符串)。
// insert OK
zadd myindex 712321 '{"the_same":"JSON"}'
// failed to insert, members should be unique
zadd myindex 712322 '{"the_same":"JSON"}'
为了解决这个问题,可以将key和json字符串结合起来,使其唯一:
zadd myindex 712321 '7:12:321-{"the_same":"JSON"}'
zadd myindex 712321 '7:12:322-{"the_same":"JSON"}'