Redis-常见数据类型(修改ing)

1. 预备知识

redis按照键值对的方式存储数据

1.1 基本全局命令

KEYS

返回所有满⾜样式(pattern)的key,⽀持如下统配样式:

  • h?llo 匹配hello,hallo,hxllo
  • h*llo 匹配hllo,heeeello
  • h[ae]llo 只匹配hallo hello
  • h[^e]llo 匹配除hello,heee..llo以外的
  • h[a-b]llo 配置hallo,hbllo

KEYS pattern                O(N)

注意:

keys命令的时间复杂度是O(N),

所以,在生产环境上,一般禁止使用此命令,尤其是keys *

 

EXISTS

判断某个key是否存在

EXISTS key [key ...]               O(1)

 

注:

分开的写法,会产生更多轮次的网络通信,效率比较低,成本比较高

DEL

删除指定的key

DEL key [key ...]                   O(1)

 

EXPIRE

为指定的key添加秒级的过期时间

EXPIRE key seconds            O(1)

 

TTL

获取指定key的过期时间,秒级

TTL key           O(1)

[面试题]redis的key的过期策略是怎么实现的?

一个redis中可能同时存在很多key,这些key中可能有很大一部分都有过期时间,那redis服务器怎么知道哪些key已经过期要被删除,哪些key还没过期?

如果之间遍历所有的key,显然不行,效率太低

整体的策略为:定期删除+惰性删除

定期删除:

每次抽取一部分,进行验证过期时间,保证这个抽取检查的过程,足够快

这里对定期删除的时间,为什么有明确的要求呢?

因为redis是单线程程序,如果扫描过期key消耗的时间太多,就可能导致正常处理请求命令被阻塞

惰性删除:

假设这个key已经到过期时间了,但是暂时还没删除,key还存在

紧接着,后面又一次访问,正好用到了这个key,于是这次访问就会让redis服务器触发删除这个key的操作,返回一个nil

虽然有上述的两种策略结合,但是整体效果一般,仍然会有很多过期的key残留,redis为了进行补充,提供了一系列的内存淘汰策略

定时器(Redis并未使用)

①基于优先级队列/堆

正常的队列是先进先出

优先级队列是按照指定的优先级先出

在redis过期key的场景中,就可以通过"过期时间越早,优先级越高"

现在假定有很多key设置了过期时间,就可以把这些key加入到一个优先级队列中,指定优先级规则是过期时间早的,先出队列

队首元素,就是最早过期的key

此时定时器只要分配一个线程,让这个线程去检查队首元素,看是否过期即可,如果队首还没过期,后续元素一定没过期

此时,扫描线程只需要盯住这一个队首元素即可

另外在扫描线程检查队首元素过期时间时,也不能太频繁

可以根据当前时刻和队首元素的过期时间,设置一个等待,当时间差不多了,系统再唤醒这个线程

此时扫描线程不需要高频扫描队首元素,把cpu的开销也节省下来了

万一在线程休眠的时候,来了一个新任务,是11:00执行

可以在新任务添加的时候,唤醒一下刚才的线程,重新检查一下队首元素,再根据时间差距重新调整阻塞时间即可

②基于时间轮实现的定时器

把时间划分成很多小段

每个小段上都挂着一个链表,每个链表都代表一个要执行的任务

(相当于一个函数指针,以及对应的参数什么的)

此时这个指针,就会每隔固定的间隔,每次走到一个格子,就把这个格子上链表的任务尝试执行一下

对于时间轮来说,每个格子是多少时间,一共多少个格子,都是需要根据实际场景设置

 

TYPE 

返回key对应的数据类型

TYPE key             O(1)

 

1.2 数据结构和内部编码

Redis的5种数据类型:

string(字符串)、list(列 表)、hash(哈希)、set(集合)、zset(有序集合)

有序集合,是除了存储member之外,还需要存储一个score 

实际上Redis针对每种数据结构都有⾃⼰的底层内部编码实现,⽽且是多种实现,这样Redis会在合适的场景选择合适的内部编码

内部编码:

数据结构内部编码
string

raw

int

embstr

hash

hashtable

ziplist

list

linkedlist

ziplist

set

hashtable

intset

zset

skiplist

ziplist

  • ziplist:压缩列表,能够节省空间 
  • quicklist:兼顾linkedlist和ziplist的优点,把空间和效率都兼顾
  • skiplist:跳表,也是链表,不同于普通链表,每个节点上有多个指针域,巧妙地搭配这些指针域地指向,就可以做到,时间复杂度O(logN)

通过object encoding命令查询内部编码

Redis 这样设计有两个好处:

1可以改进内部编码,⽽对外的数据结构和命令没有任何影响,这样⼀旦开发出更优秀的内部编码, ⽆需改动外部数据结构和命令

2) 多种内部编码实现可以在不同场景下发挥各⾃的优势,例如ziplist⽐较节省内存,但是在列表元素⽐较多的情况下,性能会下降,这时候Redis会根据配置选项将列表类型的内部实现转换为 linkedlist,整个过程⽤⼾同样⽆感知

1.3 单线程架构

引入

redis只使用一个线程,处理所有的命令请求,不是说一个redis服务器进程内部真的就只有一个线程,其实也有多个线程,多个线程在处理网络IO

假设,有多个客户端,同时操作一个服务器:

 

当前这两个客户端,也相当于"并发"发起请求了

那服务器是否会存在类似的线程安全问题呢?

并不会,redis服务器实际上是单线程模型,保证了当前收到的这多个请求是串行执行的

多个请求同时到达redis服务器,也是要现在在队列中排队,在等待redis服务器一个一个的取出里面的命令再执行

微观上讲,redis服务器是串行/顺序执行这多个命令的

redis虽然是单线程模型,为什么效率这么高,速度这么快?

  • redis访问内存,数据库则访问硬盘
  • redis的核心功能,比数据库简单.数据库对于数据的插入删除查询,都有更复杂的功能支持,会花费更多的开销
  • 单线程模型,避免了一些不必要的线程竞争开销.redis每个基本操作,都是短平快的,不会特别消耗cpu
  • 处理网络IO的时候,使用了epoll这样的IO多路复用机制 (一个线程,管理多个socket)

注:

虽然单线程给Redis带来很多好处,但还是有⼀个致命的问题:

对于单个命令的执⾏时间都是有要求的。如果某个命令执⾏过⻓,会导致其他命令全部处于等待队列中,迟迟等不到响应,造成客⼾端的阻塞,对于Redis这种⾼性能的服务来说是⾮常严重的,所以Redis是⾯向快速执⾏场景的数据库

2. String字符串

2.1 常见命令

SET

如果key之前存在,则覆盖,⽆论原来的数据类型是什么

之前关于此key的TTL也全部失效

SET key value [ EX seconds|PX milliseconds] [NX|XX]

  • EX seconds⸺使⽤秒作为单位设置key的过期时间。
  • PX milliseconds⸺使⽤毫秒作为单位设置key的过期时间。
  • NX ⸺只在key不存在时才进⾏设置,即如果key之前已经存在,设置不执⾏。
  • XX ⸺只在key存在时才进⾏设置,即如果key之前不存在,设置不执⾏

 

 

GET

获取key对应的value

如果key不存在,返回nil

如果value的数据类型不是string,会报错

GET key

 

MGET

⼀次性获取多个key的值。

如果对应的key不存在或者对应的数据类型不是string,返回nil 

MGET key [key ...]

 

MSET

⼀次性设置多个key的值 

MSET key value [key value ...]

 

SETNX

设置key-value但只允许在key之前不存在的情况下

SETNX key value

 

2.2 计数命令

INCR

针对value+1

此时key对应的value必须是整数

如果key不存在,则视为key对应的value是0

INCR key

 

INCRBY

针对value+n

此时key对应的value必须是整数

如果key不存在,则视为key对应的value是0

INCRBY key decrement

 

DECR 

针对value-1

此时key对应的value必须是整数

如果key不存在,则视为key对应的value是0

DECR key

 

DECYBY

针对value-n

如果key不存在,则视为key对应的value是0

此时key对应的value必须是整数

DECRBY key decrement 

 

INCRBYFLOAT

将key对应的string表⽰的浮点数加减上对应的值

只能用加上负数的形式实现减法

运算的操作数可以是浮点数

INCRBYFLOAT key increment

 

2.3 其它命令

APPEND

如果key已经存在并且是⼀个string,命令会将value追加到原有string的后边

如果key不存在, 则效果等同于SET命令 

APPEND KEY VALUE

 

注意:

qppend返回值,长度的单位是字节

redis的字符串,不会对字符编码做出任何处理

当前xshell终端,默认的字符编码是utf8

一个汉字在utf8字符集中,通常是三个字节

在启动redis客户端时,加上--raw,就可以使客户端自动把二进制数据尝试翻译

 

GETRANGE

返回key对应的string的⼦串,左闭右闭。

可以使⽤负数表⽰倒数: -1代表倒数第⼀个字符

超过范围的偏移量会根据string的⻓度调整成正确的值 

GETRANGE key start end

 

 

SETRANGE

覆盖字符串的⼀部分,从指定的偏移开始

offset 偏移量,从第几个字节,开始进行替换

SETRANGE key offset value

如果当前的value是一个中文字符串,进行setrange的时候,可能会出问题: 

 

setrange对不存在的key也可以进行操作,不过会把offset之前的内容填充为0x00:

 

STRLEN

获取key对应的string的⻓度,单位是字节

STRLEN key

2.4 命令总结

命令执行结果时间复杂度
set设置key的值是valueO(k),k是键个数
get获取key的值O(1)
del删除指定的keyO(k),k是键个数
mset批量设置指定的key和valueO(k),k是键个数
mget批量获取key的值O(k),k是键个数
incr指定的key的值+1O(1)
decr指定的key的值-1O(1)
incrby指定的key的值+nO(1)
decrby指定的key的值-nO(1)
incrbyfloat指定的key的值+nO(1)
append指定的key的值追加valueO(1)
strlen获取指定key的值的⻓度O(1)
setrange覆盖指定key的从offset开始的部分值O(n),n是字符 串⻓度,通常视 为O(1)
getrange获取指定key的从start到end的部分值O(n),n是字符 串⻓度,通常视 为O(1)

2.5 内部编码

  • int:64位/8个字节的⻓整型
  • embstr:压缩字符串,⼩于等于39个字节的字符串
  • raw:普通字符串,⼤于39个字节的字符串 

 

2.6 典型使用场景

缓存功能 

 

整体思路:

应用服务器访问数据的时候,先查询redis

如果redis上数据存在,就直接从redis取数据交给服务器,不再访问数据库

如果redis上数据不存在,再读取mysql,把读到的数据给应用服务器,通过把数据写入redis 

redis这样的缓存,经常用来存储"热点数据"


上述策略,存在一个问题:

随着时间的推移,会有更多的key在redis上访问不到,从而会读取mysql写入redis,那么redis的数据不是会更多么?

1)把数据写入redis的同时,设置一个过期时间

2)redis在内存不足时,提供"淘汰策略"

计数功能

使⽤Redis作为计数的基础⼯具,它可以实现快速计数、查询缓存的功能,同时数据可以异步处理或者落地到其他数据源

例如:

⽤⼾每播放⼀次视频,相应的视频播放数就会⾃增1

 

redis不擅长数据统计:

比如,统计播放量前100的视频有哪些,基于redis就会很麻烦,而mysql一个sql就搞定了 

 

共享会话

①Session分散存储: 

 

如果每隔应用服务器,维护自己的会话数据,彼此之间不共享,用户请求访问到不同的服务器上,就会出现一些不能正确处理的情况 

②Redis集中管理Session:

 

 

手机验证码

为了短信接⼝不会频繁访问,会限制⽤⼾每分钟获取验证码的频率

例如:⼀分钟不能超过5次 

 

3. Hash哈希

 

3.1 常见命令

HSET

设置hash中指定的字段(field)的值(value)

HSET key field value [field value ...]

 

HGET

获取hash中指定字段的值

HGET key field

 

 

HEXISTS

判断hash中是否有指定的字段

HEXISTS key field

 

HDEL

删除hash中指定的字段

HDEL key field [field ...] 

 

HKEYS

获取hash中的所有字段

HKEYS key 

  

HVALS

获取hash中的所有的值

HVALS key

 

 

HGETALL

获取hash中的所有字段以及对应的值

HGETALL key

 

HMGET

⼀次获取hash中多个字段的值

HMGET key field [field ...] 

 

HLEN

获取hash中的所有字段的个数

HLEN key 

 

HSETNX

在字段不存在的情况下,设置hash中的字段和值 

HSETNX key field value

 

HINCRBY

将hash中字段对应的数值添加指定的值

HINCRBY key field increment 

 

HINCRBYFLOAT

HINCRBY的浮点数版本

HINCRBYFLOAT key field increment 

 

3.2 命令总结

命令执⾏效果时间复杂度
hset 设置值O(1)
hget获取值O(1)
hdel删除fieldO(k), k 是field 个数
hlen计算field个数O(1)
hgetall获取所有的field-valueO(k), k 是field 个数
hmget批量获取field-valueO(k), k 是field 个数
hmset批量获取field-valueO(k), k 是field 个数
hexists判断field是否存在O(1)
hkeys获取所有的fieldO(k), k 是field 个数
hvals获取所有的valueO(k), k 是field 个数
hsetnx设置值,但必须在field不存在时才能设置成功O(1)
hincrby对应field-value+nO(1)
hincrbyfloat对应field-value+nO(1)
hstrlen计算value的字符串⻓度O(1)

3.2 内部编码

  • ziplist(压缩列表):当哈希类型元素个数⼩于hash-max-ziplist-entries配置(默认512个)、 同时所有值都⼩于hash-max-ziplist-value配置(默认64字节)时,Redis会使⽤ziplist作为哈 希的内部实现,节省内存空间。进行读写元素时,速度比较慢
  • hashtable(哈希表):当哈希类型⽆法满⾜ziplist的条件时,Redis会使⽤hashtable作为哈希 的内部实现,因为此时ziplist的读写效率会下降,⽽hashtable的读写时间复杂度为O(1)。 

1)当field个数⽐较少且没有⼤的value时,内部编码为ziplist:

 

2)当有value⼤于64字节时,内部编码会转换为hashtable:

3)当field个数超过512时,内部编码也会转换为hashtable

 

3.4 典型使用场景

用户信息 

关系型数据表保存⽤⼾信息:

映射关系表⽰⽤⼾信息:

使用hash的方式表示UserInfo,,就可以使用field表示对象的每个属性(数据表的每个列),此时就可以很方便的修改/获取任何一个属性的值,但是付出了更多空间的代价

使用string的方式表示UserInfo,万一只想获取或者修改其中的某个field, 就需要把整个json都读出来,解析成对象,操作field,再重写转成json字符串写回去

相⽐于使⽤JSON格式的字符串缓存⽤⼾信息,哈希类型变得更加直观,并且在更新操作上变得更灵活

哈希类型是稀疏的,⽽关系型数据库是完全结构化的,例如哈希类型每个键可以有不同的field,⽽ 关系型数据库⼀旦添加新的列,所有⾏都要为其设置值,即使为null

关系数据库可以做复杂的关系查询,⽽Redis去模拟关系型复杂查询,例如联表查询、聚合查询等 基本不可能,维护成本⾼

4. List列表

 

列表中允许有重复元素

元素是有序的(位置颠倒后的list不等价)

4.1 常见命令

LPUSH

头插

LPUSH key element [element ...]

 

LPUSHX

在key存在时,头插

不存在,直接返回

LPUSHX key element [element ...]

 

 

RPUSH

尾插

RPUSH key element [element ...]

 

RPUSHX 

在key存在时,尾插

RPUSHX key element [element ...]

 

LRANGE

获取从start到end区间的所有元素,左闭右闭

LRANGE key start stop

 

 

LPOP

头删

LPOP key

 

RPOP

尾删

RPOP key

 

LINDEX

获取从左数第index位置的元素

LINDEX key index

 

LINSERT

在特定位置插⼊元素

LINSERT key <BEFORE|AFTER> pivot element  

 

LLEN

获取list⻓度 

LLEN key

 

4.2 阻塞版本命令

在列表中有元素的情况下,阻塞和⾮阻塞表现是⼀致的

如果列表中没有元素,⾮阻塞版本会返回nil

但阻塞版本会根据timeout,阻塞⼀段时间,期间Redis可以执⾏其他命令,但要求执⾏该命令的客⼾端会表现为阻塞状态,如果没有阻塞时间,就阻塞到不为空

此处的blpop和brpop看起来阻塞很久,但实际上不会对redis服务器产生负面影响

可以同时尝试获取多个key的列表的元素,多个key对应多个list,哪个list有元素,就返回哪个元素

多个客户端同时执行pop,则最先执行命令的客户端会得到弹出的元素

BLPOP

LPOP的阻塞版本

BLPOP key [key ...] timeout 

BRPOP 

RPOP的阻塞版本

BRPOP key [key ...] timeout

1)针对一个非空的列表进行操作:

返回的结果相当于一个pair,一方面告诉我们当前的数据来自哪个key,一方面告诉我们取得的数据是什么

2)针对一个空的列表进行操作:

3)针对多个key进行操作:

此时,只有key3有元素

4.3 命令总结

操作类型命令时间复杂度
添加

rpush

lpush

linsert

lrange

O(k),k是元素个数

O(k),k是元素个数

O(n),n是pivot距离头尾的距离

查找

lrange

lindex

llen

O(s+n),s是start偏移量,n是start到end的范围

O(n),n是索引的偏移量

O(1)

删除

lpop

rpop

lremkey

ltrim

O(1)

O(1)

O(k),k是元素个数

O(k),k是元素个数

修改lsetO(n),n是索引的偏移量
阻塞操作blpop/brpopO(1)

 

4.4 内部编码

  • ziplist(压缩列表):当列表的元素个数⼩于list-max-ziplist-entries配置(默认512个),同时 列表中每个元素的⻓度都⼩于list-max-ziplist-value配置(默认64字节)时,Redis会选⽤ ziplist来作为列表的内部编码实现来减少内存消耗
  • linkedlist(链表):当列表类型⽆法满⾜ziplist的条件时,Redis会使⽤linkedlist作为列表的内 部实现

1)当元素个数较少且没有⼤元素时,内部编码为ziplist:

quicklist相当于链表和压缩列表的结合,整体还是一个链表,链表的每个节点,是一个压缩列表

2)当元素个数超过512时,内部编码为linkedlist

3)当某个元素的⻓度超过64字节时,内部编码为linkedlist

4.5 典型使用场景 

消息队列

生产者消费者模型

①Redis阻塞消息队列模型:

谁先执行的这个brpop指令,谁就能拿到这个新来的元素

这样的设定,构成一个"轮询"式的效果

消费者1拿到元素之后,就从brpop中返回了,如果消费1还想继续消费,就需要重写执行brpop~ 

②分频道的消息队列:

不同的消费 者可以通过brpop不同的键值,实现订阅不同频道的理念 

 

多个频道的场景十分常见:

比如,一个通道用来发送视频,一个用来点赞,一个用来评论~

搞成多个频道,就可以在某种数据发生问题的时候,不会对其它数据造成影响(解耦合)

选择列表类型时:

同侧存取(lpush+lpop或者rpush+rpop)为栈

异侧存取(lpush+rpop或者rpush+lpop)为队列

数组 

①mysql表示学生和班级信息:

②redis:

就可以很方便的实现"查询指定班级中有哪些学生"

5. Set集合

元素无序

不能重复(唯一) 

5.1 常见命令

SADD

重复的元素⽆法添加到set中

SADD key member [member ...] 

SMEMBERS

获取⼀个set中的所有元素

元素间的顺序是⽆序的 

SMEMBERS key

 

SISMEMBER

判断⼀个元素在不在set中 

SISMEMBER key member

 

SCARD

获取⼀个set中的元素个数

SCARD key

 

SPOP

从set中删除并返回⼀个或者多个元素

由于set内的元素是⽆序的,所以取出哪个元素实际是随机的

SPOP key [count]

 

SMOVE

将⼀个元素从源set取出并放⼊⽬标set中

要移动的元素在source中不存在,返回0,移动失败

SMOVE source destination member

 

SREM

将指定的元素从set中删除 

SREM key member [member ...]

 

5.2 集合间操作

SINTER(交集) 

获取给定set的交集中的元素

SINTER key [key ...]

 

SINTERSTORE

获取给定set的交集中的元素并保存到⽬标set中

SINTERSTORE destination key [key ...]

SUNION(并集)

 获取给定set的并集中的元素

SUNION key [key ...]

SUNIONSTORE

获取给定set的并集中的元素并保存到⽬标set中 

SUNIONSTORE destination key [key ...]

 

SDIFF(差集)

获取给定set的差集中的元素 

SDIFF key [key ...]

SDIFFSTORE

获取给定set的差集中的元素并保存到⽬标set中

SDIFFSTORE destination key [key ...] 

5.3 命令总结

命令时间复杂度
saddO(k),k是元素个数
sremO(k),k是元素个数
scardO(1)
sismemberO(1)
srandmemberO(n),n是count
spopO(n),n是count
smembersO(k),k是元素个数
sinterO(m*k),k是⼏个集合中元素最⼩的个数,m是键个数
sunionO(k),k是多个集合的元素个数总和
sdiffO(k),k是多个集合的元素个数总和

5.4 内部编码

  • intset(整数集合):当集合中的元素都是整数并且元素的个数⼩于set-max-intset-entries配置 (默认512个)时,Redis会选⽤intset来作为集合的内部实现,从⽽减少内存的使⽤。
  • hashtable(哈希表):当集合类型⽆法满⾜intset的条件时,Redis会使⽤hashtable作为集合 的内部实现。

1)当元素个数较少并且都为整数时,内部编码为intset:

2)当元素个数超过512个,内部编码为hashtable

3)当存在元素不是整数时,内部编码为hashtable:

5.5 典型使用场景

保存用户的"标签

用户画像:根据信息分析用户的特征,转化为"标签"(简短的字符串), 保存在set里

计算用户之间的共同好友

 基于集合求交集

统计UV

去重~

一个互联网产品,根据PV,UV衡量用户量,每个用户访问服务器,就会产生一个UV,但是同一个用户多次访问, 不会使UV增加,通过set来实现去重

6. Zset有序集合

给zset的中member引入了一个属性score(浮点类型)

进行排序的时候,就是依照此处的分数大小进行升序/降序,默认升序

score可以重复,member唯一

不能把member和score理解为键值对,键值对有明显的角色区分,一定是键=>值,而有序集合可以互相匹配

6.1 常见命令

ZADD

ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...] 

  • XX:仅仅⽤于更新已经存在的元素,不会添加新元素。 
  • NX:仅⽤于添加新元素,不会更新已经存在的元素。 
  • CH:默认情况下,ZADD返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次更新的元素的个数。 
  • INCR:此时命令类似ZINCRBY的效果,将元素的分数加上指定的分数。此时只能指定⼀个元素和 分数。

 

ZCARD

获取zset中的元素个数

ZCARD key 

ZCOUNT

返回分数在min和max之间的元素个数 

ZCOUNT key min max

 

ZRANGE

返回指定区间⾥的元素,分数按照升序

带上WITHSCORES可以把分数也返回

ZRANGE key start stop [WITHSCORES] 

ZREVRANGE

返回指定区间⾥的元素,分数按照降序

带上WITHSCORES可以把分数也返回,,并且功能合并到ZRANGE中

ZREVRANGE key start stop [WITHSCORES]

 

ZRANGEBYSCORE

返回分数在min和max之间的元素 

ZRANGEBYSCORE key min max [WITHSCORES]

ZPOPMAX

删除并返回分数最⾼的count个元素 

ZPOPMAX key [count]

 

此处疑问:

此处删除的是最大值,而有序集合,最大值就相当于最后一个元素(尾删),那为什么不把最后一个元素的位置记录下来,后续删除就可以o(1)了??

O(logN)=>此处如果N不是特别的大,基本可以近似看作O(1)的

优化空间??

BZPOPMAX

ZPOPMAX的阻塞版本

BZPOPMIN key [key ...] timeout

key标识了有序集合

ZPOPMIN

删除并返回分数最低的count个元素

ZPOPMIN key [count]

BZPOPMIN

ZPOPMIN的阻塞版本

BZPOPMIN key [key ...] timeout

ZRANK

返回指定元素的排名,升序

ZRANK key member

 

ZREVRANK

返回指定元素的排名,降序

ZREVRANK key member

ZSCORE

返回指定元素的分数

ZSCORE key member

 

ZREM

删除指定的元素 

ZREM key member [member ...]

ZREMRANGEBYRANK

按照排序,升序删除指定范围的元素,左闭右闭

ZREMRANGEBYRANK key start stop

ZREMRANGEBYSCORE

按照分数删除指定范围的元素,左闭右闭

ZREMRANGEBYSCORE key min max

ZINCRBY

为指定的元素的关联分数添加指定的分数值 

ZINCRBY key increment member

 

6.2 集合间操作

ZINTERSTORE 

求出给定有序集合中元素的交集并保存进⽬标有序集合中,在合并过程中以元素为单位进⾏合并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE ]

 

ZUNIONSTORE

求出给定有序集合中元素的并集并保存进⽬标有序集合中,在合并过程中以元素为单位进⾏合并,元 素对应的分数按照不同的聚合⽅式和权重得到新的分数

ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE ]

 

 

6.3 命令总结

命令时间复杂度

zadd

O(k *log(n)),k 是添加成员的个数,n是当前有序集合的元 素个数
zcardO(1)
zscoreO(1)
zrankO(log(n)),n是当前有序集合的元素个数
zremO(k*log(n)),k是删除成员的个数,n是当前有序集合的元 素个数
zincrbyO(log(n)),n是当前有序集合的元素个数
zrangeO(k+log(n)),k是获取成员的个数,n是当前有序集合的元 素个数
zrevrangeO(k+log(n)),k是获取成员的个数,n是当前有序集合的元 素个数
zrangebyscoreO(k+log(n)),k是获取成员的个数,n是当前有序集合的元 素个数
zrevrangebyscoreO(k+log(n)),k是获取成员的个数,n是当前有序集合的元 素个数
zcountO(log(n)),n是当前有序集合的元素个数
zremrangebyrankO(k+log(n)),k是获取成员的个数,n是当前有序集合的元 素个数
zremrangebyscoreO(k+log(n)),k是获取成员的个数,n是当前有序集合的元 素个数
zinterstorO(n*k)+O(m*log(m)),n是输⼊的集合最⼩的元素个数, k是集合个数,m是⽬标集合元素个数
zunionstoreO(n)+O(m*log(m)),n是输⼊集合总元素个数,m是⽬标 集合元素个数

6.4 内部编码

  • ziplist(压缩列表):当有序集合的元素个数⼩于zset-max-ziplist-entries配置(默认128个), 同时每个元素的值都⼩于zset-max-ziplist-value配置(默认64字节)时,Redis会⽤ziplist来作 为有序集合的内部实现,ziplist可以有效减少内存的使⽤。
  • skiplist(跳表=>复杂链表o(logN)):当ziplist条件不满⾜时,有序集合会使⽤skiplist作为内部实现,因为此时 ziplist的操作效率会下降 

1)当元素个数较少且每个元素较⼩时,内部编码为ziplist:

2)当元素个数超过128个,内部编码skiplist

3)当某个元素⼤于64字节时,内部编码skiplist:

6.5 典型使用场景

排行榜系统 

①比如游戏玩家排行:

只需要把玩家信息和对应的分数放到有序集合即可,自动就形成了排行榜

随时可以按照下标,分数进行范围查询

修改分数也是比较方便的,排行顺序也会自动调整

但也有的排行榜要复杂一些

②如微博热度:

要考虑浏览量,点赞量等多个因素的综合数值,计算权重weight 

此时可以借助zinterstore/zunionstore按照加权方式处理

就可以把上述每个维度的数值都放到一个有序集合中,member就是微博id,score就是各自维度的数值,通过集合间运算得到结果的集合的分数就是热度,从而排行榜就出来了

7. 补充类型

Streams

模拟实现事件传播的机制

那么事件是干什么的?我们也不知道它什么时候出现,只能等这个事情出现了之后,采取动作

比如:一旦着火,立即灭火,没着火,就等着

此处的着火就是"事情",灭火就是"事件触发的回调函数"

Geospatial

用来存储坐标(经纬度)

存储一些点之后,就可以让用户给定一个坐标,去从刚才存储的点进行查找

这个功能在地图中很重要

HyperLogLog

估算集合中的元素个数

之前在Set应用场景中提到了统计UV,但是有一个问题,UV数据量很大,就会消耗更多内存空间

而HyperLogLog不存储元素的内容,但是能记录"元素的特征",从而在新增元素的时候,能够知道当前新增的元素是一个已经存在的,还是新的

存储元素的时候,提取特征的过程是不可逆的,不能通过特征得到内容(信息量丢失了)

Bitmaps

使用bit位表示整数

位图本质上,还是一个集合,是set类型针对整数的特化版,会存储元素

比较高效,更节省空间

Bitfields 

和C中的位域,十分相似,更精确地进行位操作

 

可以理解为一串二进制序列(字节数组),同时把这个字节数组的某几个位,赋予特定的含义,并且可以进行读取/修改/算术运算等操作

相比于String/hash,节省空间

8. 渐进式遍历

keys *一次性把整个redis中所有的key都获取到,这个操作比较危险,可能会阻塞redis服务器 

Redis 使⽤scan命令进⾏渐进式遍历,进⽽解决直接使⽤keys获取键时可能出现的阻塞问题

每执行一个命令,只获取其中的一小部分

每次scan命令的时间复杂度是O(1),但是要完整地完成所有键的遍历,需要执⾏多次scan

SCAN

 

注意:

  • cursor不能理解成"下标",不是一个连续递增的整数,仅仅就是一个字符串
  • 光标这个概念,客户端是不能热认识的,redis服务器则知道对应的元素位置

 

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]

count限制这一次遍历能够获取到多少个元素,默认是10 

count只是一个建议,但是写入的count和实际返回的key的个数不一定相同,也不会差太多

时间复杂度:O(1)

返回值:下⼀次scan的游标(cursor)以及本次得到的键 

注意:

  • 这里的渐进式遍历,在遍历过程中,不会在服务器这边存储任何状态信息,此处的遍历是可以随时终止的,不会对服务器产生任何的副作用
  • 渐进性遍历scan虽然解决了阻塞的问题,但如果在遍历期间键有所变化(增加、修改、删除),可能导致遍历时键的重复遍历或者遗漏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1550474.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Java-数据结构-Map和Set-(二)-哈希表 |ू・ω・` )

文本目录&#xff1a; ❄️一、哈希表&#xff1a; ☑ 1、概念&#xff1a; ☑ 2、冲突-概念&#xff1a; ☑ 3、冲突-避免&#xff1a; ☞ 1&#xff09;、避免冲突-哈希函数的设计&#xff1a; ☞ 2&#xff09;、避免冲突-负载因子调节(重点)&#xff1a; ☑ 4、冲突-解决&…

宠物空气净化器该怎么选?希喂、美的、有哈这三款有推荐的吗?

终于要到国庆了&#xff0c;这可是打工人除春节外最长的假期&#xff01;在外上班后&#xff0c;回家的次数越来越少了&#xff0c;这次国庆肯定要回去陪陪父母。这票是真难买啊&#xff0c;候补了我一个多星期才买到。本来以为最困难的问题已经解决了&#xff0c;又想到我家猫…

有通话质量更好的蓝牙耳机推荐吗?高品质的平价开放式耳机推荐

个人认为开放式耳机在通话方面还是表现不错的&#xff0c;主要有以下几个原因&#xff1a; 首先&#xff0c;在麦克风设计与配置方面&#xff1a; 拥有高品质麦克风硬件。优质的开放式耳机往往会配备高性能的麦克风&#xff0c;这些麦克风灵敏度较高&#xff0c;能够精准地捕捉…

情感短视频素材下载推荐

在制作热门的情感短视频时&#xff0c;优质的素材是不可或缺的。作为一名资深视频剪辑师&#xff0c;今天我将为你推荐几个可以下载高清无水印情感视频素材的网站&#xff0c;助你轻松找到创作灵感。 蛙学网 蛙学网是国内领先的视频素材平台&#xff0c;专注于情感和治愈类视频…

TypeScript是基于LLM上层研发的受益者

TypeScript优在哪里 TypeScript是一种由微软开发的开源编程语言&#xff0c;它是JavaScript的一个超集&#xff0c;添加了类型系统和一些其他特性。TypeScript的优势在于&#xff1a; 静态类型检查&#xff1a;TypeScript的最大卖点是它的静态类型系统。这允许开发者在编写代码…

11.C++程序中的常用函数

我们将程序中反复执行的代码封装到一个代码块中&#xff0c;这个代码块就被称为函数&#xff0c;它类似于数学中的函数&#xff0c;在C程序中&#xff0c;有许多由编译器定义好的函数&#xff0c;供大家使用。下面就简单说一下&#xff0c;C中常用的函数。 1.sizeof sizeof函…

AI预测福彩3D采取888=3策略+和值012路或胆码测试9月28日新模型预测第101弹

经过100多期的测试&#xff0c;当然有很多彩友也一直在观察我每天发的预测结果&#xff0c;得到了一个非常有价值的信息&#xff0c;那就是9码定位的命中率非常高&#xff0c;100多期一共只错了12次&#xff0c;这给喜欢打私房菜的朋友提供了极高价值的预测结果~当然了&#xf…

Learn OpenGL In Qt之炫酷进度条

竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~ 公众号&#xff1a; C学习与探索 | 个人主页&#xff1a; rainInSunny | 个人专栏&#xff1a; Learn OpenGL In Qt 文章目录 设计实现目录结构需要哪些类接口设计关键函数 实现效果Shader解析GLSL基本函数clampsmoothstep 实现分析效…

2.点位管理——帝可得后台管理系统

目录 前言点位管理菜单模块1.需求说明2.库表设计3.生成基础代码0 .使用若依代码生成器最终目标1.创建点位管理2.添加数据字典3.配置代码生成信息4.下载代码并导入项目 4.优化菜单——点位管理1.优化区域管理2.增加点位数3. 合作商 前言 提示&#xff1a;本篇介绍点位管理模块&…

[论文精读]AI-Guardian: Defeating Adversarial Attacks using Backdoors

会议名称&#xff1a;2023 IEEE Symposium on Security and Privacy (SP) 发布链接&#xff1a;AI-Guardian: Defeating Adversarial Attacks using Backdoors | IEEE Conference Publication | IEEE Xplore 中文译名&#xff1a;AI-Guardian:利用后门防御对抗攻击 阅读原因…

记一次教学版内网渗透流程

信息收集 如果觉得文章写的不错可以共同交流 http://aertyxqdp1.target.yijinglab.com/dirsearch dirsearch -u "http://aertyxqdp1.target.yijinglab.com/"发现 http://aertyxqdp1.target.yijinglab.com/joomla/http://aertyxqdp1.target.yijinglab.com/phpMyA…

IT基础监控范围和对象

监控易作为一款由美信时代独立自主研发的分布式一体化集中监控平台&#xff0c;其监控范围极为广泛&#xff0c;几乎涵盖了所有主流的IT基础设施以及相关的设备和系统。以下是对监控易监控范围的详细介绍&#xff1a; 一、IT基础资源监控 服务器硬件监控&#xff1a;监控易支…

fmql之Linux阻塞和非阻塞IO

继续学习正点原子吧。 概念简介 什么是阻塞、非阻塞IO 阻塞/非阻塞访问的代码示例 等待队列&#xff08;阻塞访问使用&#xff09; 轮询&#xff08;非阻塞访问使用&#xff09; poll操作函数的使用&#xff08;轮询的一种&#xff09; 阻塞IO的实验 blockio.c blockioAPP.c 运…

大模型能力扩展之——提示词(Prompt),知识库,思维链(CoT)和Agent(代理)

前言 “大模型的推理能力配合外部工具才能真正发挥大模型的作用” 在学习和使用大模型的过程中&#xff0c;我们会发现大模型只能用来进行一下简单的问答&#xff1b;一旦涉及到复杂的问题&#xff0c;大模型就无能为力了。 其原因就在于我们并不会使用大模型&#xff0c;或…

【韩顺平Java笔记】第3章:变量

只记录我觉得重点的&#xff0c;自用&#xff0c;如果有漏的请自己看视频 文章目录 33. 内容梳理34. 变量原理34.1 为什么需要变量35. 变量概念35.1 概念35.2 变量使用的基本步骤36. 变量入门36.1 变量使用入门案例 37. 变量细节37.1 变量使用注意事项 38. 加号使用38.1 程序中…

Node.js安装Express,Node.js支持Typescript以及Express支持Typescript的步骤

1. Node.js 安装Express 运行如下命令&#xff1a; $ mkdir express-demo $ cd express-demo$ npm install express $ npm install body-parser //(可选)中间件&#xff0c;用于处理 JSON, Raw, Text 和 URL 编码的数据 $ npm install cookie-parser //(可选)通过req.cookies…

如何使用ssm实现大学生校园招聘网的设计与实现

TOC ssm738大学生校园招聘网的设计与实现jsp 第1章 绪论 1.1 课题背景 二十一世纪互联网的出现&#xff0c;改变了几千年以来人们的生活&#xff0c;不仅仅是生活物资的丰富&#xff0c;还有精神层次的丰富。在互联网诞生之前&#xff0c;地域位置往往是人们思想上不可跨域…

网页WebRTC电话和软电话哪个好用?

关于WebRTC电话与软件电话哪个更好用&#xff0c;这实际上取决于多个因素&#xff0c;并没有一个绝对的答案。不过&#xff0c;我可以根据WebRTC技术的一些特点&#xff0c;以及与传统软件电话相比的优劣势&#xff0c;为你提供一个清晰的对比。 首先&#xff0c;让我们了解一下…

单细胞miloR分析(基于 KNN 图的细胞差异丰度分析方法)

通常情况下&#xff0c;对两组或多组样本进行了不同处理/干预之后&#xff0c;研究者首先会进行同种细胞亚群处理前后的细胞数量的比较&#xff0c;但在单细胞分辨率时代之后&#xff0c;即使是同一个亚群中的不同细胞也应当看成不同的样本。 那么问题就来了&#xff0c;既然应…

算法:按既定顺序创建目标数组

力扣1389 提示&#xff1a; 1 < nums.length, index.length < 100nums.length index.length0 < nums[i] < 1000 < index[i] < i 题解&#xff1a; class Solution {public int[] createTargetArray(int[] nums, int[] index) {int[] target new int[num…