Redis中的keys命令可以列出满足特定正则表达式所有的key.命令的格式为keys pattern

Redis中sorted set查找时间复杂度 redis scan时间复杂度_数组


但是它存在俩显著的缺点

  • 没有偏移量与限制个数
  • 时间复杂度是O(n)

为解决此问题,2.8版本便加入年Scan指令。
它有如下特点:

  • 时间复杂度仍为O(n),且通过游标分布进行。
  • 提供limit参数
  • 提供模式匹配功能
  • 服务器不需要为游标保存状态。
  • 返回结果会有重复
  • 遍历过程中若有数据修改,改动后的数据不一定会便利到。
  • 单次返回的结果是空的并不意味着遍历结束,而看返回的游标值。

基本用法

scan cursor [MATCH pattern] [COUNT count] cursor为设定的游标值。

先为Redis增添一些键值对

public class InsertData {
    public static void main(String[] args) {
        try(Jedis jedis = new Jedis()) {
            for (int i = 0; i < 1000; i++) {
                jedis.set("key"+i, String.valueOf(i));
            }

        }
    }
}

用法示例如下所示

Redis中sorted set查找时间复杂度 redis scan时间复杂度_redis_02

游标为何物?

在Redis中所有的key都类似于HashMap一样被存于一个数组(桶表)当中,而那个游标位置就是数组的索引。
某个游标值的得到元素的或多或少与该桶中挂载的元素有关。limit表示遍历的桶的数量,将这些桶进行模式匹配后一次性返回。

scan遍历顺序

它采用高位进位加法来遍历。使用此方法是考虑到字典的扩容与缩容时避免桶重复和遗漏。而且高位扩容过来的顺序是相邻的。

0000 -+1-> 1000 -+1-> 0100 -+1->1100.....

字典扩容

与HashMap类似,有一个将桶中元素高1位hash值是否为1,如果是移至高位,否保持不变。
比如一个元素的hash码为1001。在桶为8时,在1号位置,在扩容后(桶为16),在9号位置。

扩容、缩容后的遍历顺序

由于高位进位加法,rehash后的桶的位置是相邻的。
所以扩容后仅需找到需要遍历的原位置之后的即可。

缩容与扩容类似,不过由于将两个桶存到一起了,可能会重复遍历之前已经遍历过的内容,这大概就是要手动去重的原因吧。

渐近式rehash

就是会保留新旧两种桶表,旧找不到就去新的找。就跟CHM中加个转发结点似的感觉(底层实现是怎样的我不知道)。

scan还支持一些其他的指令,zscan、hscan等,原理类似

大Key扫描

如果某个Key过大,会造成集群环境下数据迁移时的卡顿。且扩容时会一次性申请更大的一块内存,也会造成卡顿。且被清除时,一次性回收,也会造成卡顿。
所以业务中尽量避免大key。
这种情况下也可以使用scan命令定位大key

在每隔100条指令休眠time秒。

redis-cli -h ip  -p port --bigkeys  -i time秒

!!!啊下一章原理篇了