1.问题
当zset的score有较多相同值,通过ZREVRANGEBYSCORE等命令查询时,可能出现死循环,查询不完的情况。
2.解决方案
2.1 计算offset
每次查询完一页后,计算ZREVRANGEBYSCORE查询的最小值,判断和前一个值是否相等,
- 如果相等,继续计算,最多offset是本次的page_size,那么offset加上page_size;如果出现有重复的,可将page_size*2拉取。
- 如果不相等,说明分数目前没有重复,则offset默认为1,下次查询时会偏移一个返回,不会重复。
这种方式,offset越大复杂度越高,O(offset + limit)。
2.2 构造唯一score
若使用时间戳作为分数,业务上同一时间戳有很多并发,那么说明该分数并不适合,可以构造唯一分数来解决:
score = 秒级ts *1e6 + count2.3 两次查询
使用offset虽然简单,但性能可能会有所下降,可以分两次查询:
上一次查询结果:
(last_ts, last_member)下次查询:
(ts < last_ts) OR (ts == last_ts AND member < last_member)那么命令:
ZRANGEBYSCORE key last_ts last_ts // 查到所有分数相同的,当数量 n < page_size 时 ZREVRANGEBYSCORE key (last_ts -inf LIMIT 0 (page_size - n) // 再查询分数更小的复杂度有点高,多了来回的网络开销。