Redis 二级索引和性能问题
Redis Secondary Indexes and Performance Question
我知道Redis并没有真正的二级索引的概念,但是你可以使用Z*命令来模拟一个。我对处理以下情况的最佳方式有疑问。
我们正在使用 Redis 来跟踪订单。但我们也希望能够通过 phone 号码或电子邮件 ID 找到这些订单。这是我们的数据:
> set 123 7245551212:dlw@email.com
> set 456 7245551212:dlw@email.com
> set 789 7245559999:kdw@email.com
> zadd phone-index 0 7245551212:123:dlw@email.com
> zadd phone-index 0 7245551212:456:dlw@email.com
> zadd phone-index 0 7245559999:789:kdw@email.com
我可以通过以下方式查看 phone 号码的所有订单(除了在末尾添加 'Z' 之外,还有更好的获取范围的方法吗?):
> zrangebylex phone-index [7245551212 (7245551212Z
1) "7245551212:123:dlw@dcsg.com"
2) "7245551212:456:dlw@dcsg.com"
我的问题是,这会表现良好吗?或者我们应该只创建一个由 phone 数字键入的列表,然后向该列表添加一个订单 ID?
> rpush phone:7245551212 123
> rpush phone:7245551212 456
> rpush phone:7245559999 789
> lrange phone:7245551212 0 -1
1) "123"
2) "456"
哪种方法是首选方法,尤其是与性能相关的方法?
回复:除了在末尾添加 'Z' 之外,是否有更好的方法来获取范围?
是的,使用下一个直接字符而不是添加 Z
:
zrangebylex phone-index [7245551212 (7245551213
但第二种方法肯定会提供更好的性能。
为 lexicographical indexing 使用排序集,您需要考虑:
- 元素相加
ZADD
是O(log(N))
- 查询
ZRANGEBYLEX
是 O(log(N)+M)
,其中 N 是排序集中的元素数,M 是返回的元素数
相比之下,使用列表:
您也可以使用集合(SADD
和 SMEMBERS
),不同之处在于列表允许重复并保留顺序,集合确保唯一性并且不遵守插入顺序。
ZSet 对 score 使用 skiplist,对 hashset 使用 dict。如果你添加所有具有相同分数的元素,skiplist 将变成 B-TREE 类结构,其具有 O(logN) 时间复杂度用于字典顺序搜索。
所以如果你不总是对phone号进行范围查询,那么对于以phone号为key的订单,应该使用list进行精确查询。这也适用于电子邮件(您可以使用散列来组合这两个列表)。这样查询性能会比ZSET好很多
我知道Redis并没有真正的二级索引的概念,但是你可以使用Z*命令来模拟一个。我对处理以下情况的最佳方式有疑问。
我们正在使用 Redis 来跟踪订单。但我们也希望能够通过 phone 号码或电子邮件 ID 找到这些订单。这是我们的数据:
> set 123 7245551212:dlw@email.com
> set 456 7245551212:dlw@email.com
> set 789 7245559999:kdw@email.com
> zadd phone-index 0 7245551212:123:dlw@email.com
> zadd phone-index 0 7245551212:456:dlw@email.com
> zadd phone-index 0 7245559999:789:kdw@email.com
我可以通过以下方式查看 phone 号码的所有订单(除了在末尾添加 'Z' 之外,还有更好的获取范围的方法吗?):
> zrangebylex phone-index [7245551212 (7245551212Z
1) "7245551212:123:dlw@dcsg.com"
2) "7245551212:456:dlw@dcsg.com"
我的问题是,这会表现良好吗?或者我们应该只创建一个由 phone 数字键入的列表,然后向该列表添加一个订单 ID?
> rpush phone:7245551212 123
> rpush phone:7245551212 456
> rpush phone:7245559999 789
> lrange phone:7245551212 0 -1
1) "123"
2) "456"
哪种方法是首选方法,尤其是与性能相关的方法?
回复:除了在末尾添加 'Z' 之外,是否有更好的方法来获取范围?
是的,使用下一个直接字符而不是添加 Z
:
zrangebylex phone-index [7245551212 (7245551213
但第二种方法肯定会提供更好的性能。
为 lexicographical indexing 使用排序集,您需要考虑:
- 元素相加
ZADD
是O(log(N))
- 查询
ZRANGEBYLEX
是O(log(N)+M)
,其中 N 是排序集中的元素数,M 是返回的元素数
相比之下,使用列表:
您也可以使用集合(SADD
和 SMEMBERS
),不同之处在于列表允许重复并保留顺序,集合确保唯一性并且不遵守插入顺序。
ZSet 对 score 使用 skiplist,对 hashset 使用 dict。如果你添加所有具有相同分数的元素,skiplist 将变成 B-TREE 类结构,其具有 O(logN) 时间复杂度用于字典顺序搜索。
所以如果你不总是对phone号进行范围查询,那么对于以phone号为key的订单,应该使用list进行精确查询。这也适用于电子邮件(您可以使用散列来组合这两个列表)。这样查询性能会比ZSET好很多