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 使用排序集,您需要考虑:

  • 元素相加ZADDO(log(N))
  • 查询 ZRANGEBYLEXO(log(N)+M),其中 N 是排序集中的元素数,M 是返回的元素数

相比之下,使用列表:

  • 加法RPUSHO(1)
  • 查询 LRANGEO(N),因为您从零开始。

您也可以使用集合(SADDSMEMBERS),不同之处在于列表允许重复并保留顺序,集合确保唯一性并且不遵守插入顺序。

ZSet 对 score 使用 skiplist,对 hashset 使用 dict。如果你添加所有具有相同分数的元素,skiplist 将变成 B-TREE 类结构,其具有 O(logN) 时间复杂度用于字典顺序搜索。

所以如果你不总是对phone号进行范围查询,那么对于以phone号为key的订单,应该使用list进行精确查询。这也适用于电子邮件(您可以使用散列来组合这两个列表)。这样查询性能会比ZSET好很多