我为每个州锁定的个人设置了一组ID
people/stateName:VA = {1,2,3,4,5,6}
people/stateName:TX = {7,8,9,10,11}
...
我为公司1的个人提供了一组id;
people/company:1 = {2,6,7,10}
在上面的例子中,如果我想找到所有属于公司1且生活在VA和TX状态的人,我会这样做:
SUNIONSTORE tempkey people/stateName:VA people/stateName:TX
SINTERSTORE tempkey tempkey people/company:1
数学:(A ∪ B) ∩ C
然而,在我的情况下,状态的数量是未知的,所以你必须迭代你想要的状态集的列表,组合它们,然后最终由公司交叉(你是如果你有多家公司,我必须重复这个过程)
foreach( state in state_list ){
SUNIONSTORE(tempkey_state,tempkey_state, 'people/stateName:{state}')
}
foreach( companyNumber in company_list ){
SUNIONSTORE(tempkey_company, tempkey_company, 'people/company:{companyName}')
}
SINTERSTORE(resultkey, tempkey_state, tempkey_company);
在我的真实场景中,每组都非常大,在10,000到1,000,000名成员中。然而,这个过程可能很慢(在某些情况下比SQL慢)
根据我的理解,瓶颈是SUNIONSTORE
,因为它随着每次迭代而增长,并且它具有大的O(N)
我有什么方法可以更快地做我想要的事情吗?我想到的一些解决方案
你有什么想法?
答案 0 :(得分:2)
集合的代数包括交换和分配法则,因此:
(A ∪ B) ∩ C = (C ∩ A) ∪ (C ∩ B)
Redis使用交换律来优化交集计算:它在应用算法之前对每个大小的集进行排序,以最大限度地减少操作次数。
此外,联合和交叉操作的性能主要由对象创建(涉及内存分配)的成本决定,而不是实际的联合/交集算法。
在你的例子中,我会说拥有大型国家集合的可能性高于为公司设置大型集合的可能性,所以我宁愿执行:
MULTI
SINTERSTORE tmp1 people/company:1 people/stateName:VA
SINTERSTORE tmp2 people/company:1 people/stateName:TX
SUNION tmp1 tmp2
DEL tmp1 tmp2
EXEC
这里,在Redis名称空间中实际创建的唯一对象已经是交集的结果,这可能会产生更少的对象。请注意,最后一个联合不存储结果,而是将其直接返回给客户端。
请务必使用管道来最小化网络往返次数。
如果你有几家公司,你可以在他们的集合上申请工会(如果公司集的平均规模不是太高),或者你可以每个公司多次重复这种模式(如果公司太大) )。