1. 首页
  2. 乌拉客

Redis5种数据类型

今天开始我分享一下Redis中的5种数据结构。下面我们看第一种数据结构字符串。字符串是Redis中的最基础的数据结构。我们保存到Redis中的key,也就是键,就是字符串结构的,除此之外,我们以后学习的其它数据结构,也是在字符串的基础上设计的,可见字符串结构对于Redis是多么的重要。字符串中的值虽然是字符串但是可以保存很多种类型的如:简单的字符串、JSON、XML、二进制等等。但有一点要特别注意,就是在Redis中字符串类型的值最大只能保存512MB。


img

  • 命令
  1. 设置值
set key value [EX seconds] [PX milliseconds] [NX|XX]
img

set命令有几个非必须的选项,下面我们看一下它们具体的说明

  • EX seconds:为键设置秒级过期时间
  • PX milliseconds:为键设置毫秒级过期时间
  • NX:键必须不存在,才可以设置成功,用于添加
  • XX:键必须存在,才可以设置成功,用于更新

下面我们看一下setnx和setxx命令在实际的开发中,有什么作用呢?我们知道setnx命令只有当然key不存在的时候才能设置成功,换句话说,也就是同一个key在执行setnx命令时,只能成功一次,并且由于Redis的单线程命令处理机制,即使多个客户端同时执行setnx命令,也只人有一个客户端执行成功。所以,正是基于setnx命令的这种特性,所以setnx命令可以作为分布式锁的一种解决方案。


2.获取值

get key
img

3.批量设置值

mset key value
img

4.批量获取值

mget key
img

如果有些键不存在,那么它的值将为nil也就是空,并且返回的结果,就是按照传入键的顺序返回的。

img

5.计数

incr key


incr命令用于对值做自增操作,返回的结果分为3种情况:

  • 如果值不是整数,那么返回的一定是错误
  • 如果值是整数,那么返回自增后的结果
  • 如果键不存在,那么就会创建此键,然后按照值为0自增, 就是返回1

除此之外,在Redis中除了有incr自增命令外,还提供了很多其它的有关对数字处理的命令。例如:

decr key 自减
incrby kek increment 自增指定数字
decrby key decrement 自减指定数字
incrbyfloat key increment 自增浮点数
img

6.追加值

append key value
img


append命令可以向字符串尾部追加值。


7.字符串长度

strlen key
img

由于每个中文占用3个字节,所以jilinwula这个键,返回是字符串长度为12,而不是4。


8.设置并返回原值

getset key value
img

9.设置指定位置的字符

setrange key offeset value
img

10.获取部分字符串

getrange key start end
img
  • 时间复杂度
    在Redis中执行任何命令时,都有相应的时间复杂度的,复杂度越高也就越费时间,所以在执行Redis中的命令时,如果要执行的命令复杂度越高,就越要慎重。下面是字符串命令时间复杂度类型表:
命令时间复杂度
set key valueO(1)
get keyO(1)
del keyO(k) k是键的个数
mset key valueO(k) k是键的个数
mget keyO(k) k是键的个数
incr keyO(1)
decr keyO(1)
incrby key incrementO(1)
decrby keky incrementO(1)
incrbyfloat key iincrementO(1)
append key valueO(1)
strlen keyO(1)
setrange key offset valueO(1)
getrange key start endO(n) n是字符串长度
  • 内部编码
    在Redis中字符串类型的内部编码有3种。
  • int:8个字节的长整型
  • embstr:小于等于39个字节的字符串
  • raw:大于39个字节的字符串
img

下面我们介绍第二种数据类型,哈希类型。大部分语言基本都提供了哈希类型,如Java语言中的Map类型及Python语言中的字典类型等等。虽然语言不同,但它们基本使用都是一样的。也就是都是键值对结构的。例如:

value={{field1, value1}

下面我们通过下图来直观感受一下字符串类型和哈希类型的区别。

img

Redis中哈希类型都是键值对结构的,所以要特别注意这里的value并不是指的是Redis中的key的value,而是Redis中哈希类型中的field所对应的value。

下面我们还是和介绍字符串类型一样,先是了解一下Redis中哈希类型的相关命令。

命令


一. 设置值

hset key field value 
img

我们看上图执行的命令知道,hset命令也是有返回值的。如果hset命令设置成功,则返回1,否则则返回0。除此之外Redis也为哈希类型提供了hsetnx命令。在字符串那篇文章中,我们知道,nx命令则表示key不存在的时候,才能设置成功,而在Redis中hsetnx命令则表示field不存在的时候,才能设置成功。


二. 获取值

hget key field
img


我们看hget命令和get有很大的不同,get命令在获取的时候,只要写一个名字就可以了,而hget命令则要写两个名字,第一个名字就是key 第二个名字就是field。除此之外,当然key或者field不存在时,返回的结果都是nil。


三. 删除field

hdel key field [field ...]
img

hdel命令删除的时候,也会有返回值,并且这个返回就是成功删除field的个数。当field不存在时,并不会报错,而是直接返回0。


四. 计算field个数

hlen key
img

hlen命令返回的就是当前key中field的个数,如果key不存在,则返回0。


五. 批量设置或获取field-value

hmget key field [field ...]
hmset key field value [field value ...]
img

hmset命令和hmget命令分别都是批量设置和获取值的,hmset命令没有什么要注意的,但hmget命令要特别注意,当我们获取一个不存在的key或者不存在的field时,Redis并不会报错,而是返回nil。并且有几个field不存在,则Redis返回几个nil,当整个key都不存在时,则返回全部nil(有几个field返回几个nil)。


六. 判断field是否存在

hexists key field
img

当执行hexists命令时,如果当前key包括field,则返回1,否则返回0。

七. 获取所有field

hkeys key
img

八. 获取所有value

hvals key
img

九. 获取所有的field-value

hgetall key
img

hgetall命令会返回当前key中的所有field-value,并按照顺序依次返回,也就是field-value field-value等等。


十. hincrby hincrbyfloat

hincrby key field increment
hincrbyfloat key field increment
img

hincrby命令和incrby命令的使用功能基本一样,都是对值进行增量操作的。唯一不同的就是incrby命令的作用域key,而hincrby命令的作用域则是field。


十一. 计算value的字符串长度

hstrlen key field
img

hstrlen命令返回的是当前key中field中字符串的长度,如果当前key中没有field则返回0。


哈希类型命令的时间复杂度

命令时间复杂度
hset key field valueO(1)
hget key fieldO(1)
hdel key field [field …]O(k) ,k是field个数
hlen keyO(1)
hgetall keyO(n) ,n是field总数
hmget key field [field …]O(k) ,k是field个数
hmset key field value [field value …]O(k) ,k是field个数
hexists key fieldO(1)
hkeys keyO(n) ,n是field总数
hvals keyO(n) ,n是field总数
hsetnx key field valueO(1)
hincrby key field incrementO(1)
hincrbyfloat key field incrementO(1)
hstrlen key fieldO(1)

内部编码

在Redis哈希类型的内部编码只有两种它们分别是:

  • ziplist(压缩列表):当哈希类型中元素个数小于hash-max-ziplist-entries配置(默认512个)同时所有值都小于hash-max-ziplist-value配置(默认64字节)时,Redis会使用ziplist作为哈希的内部实现。
  • hashtable(哈希表):当上述条件不满足时,Redis则会采用hashtable作为哈希的内部实现。

下面我们通过以下命令来演示一下ziplist和hashtable这两种内部编码。

  1. 当field个数比较少并且value也不是很大时候Redis哈希类型的内部编码为ziplist。
  2. 当value中的字节数大于64字节时(可以通过hash-max-ziplist-value设置),内部编码会由ziplist变成hashtable。

    因为在Redis中中文的字节数比英文的字节数大大,正常来说,一个中文占用3个字节。
  3. 当field个数超过512(可以通过hash-max-ziplist-entries参数设置),内部编码也会由ziplist变成hashtable。
    由于直接创建512个field不方便,为了更好的验证该功能,我将用程序的方式,动态创建512个field来验证此功能,下面为具体的代码。
import redis

r = redis.Redis(host='127.0.0.1', port=6379)

print('Key为【userinfo】的字节编码为【%s】' % r.object('encoding', 'userinfo').decode('utf-8'))

for i in range(1,513):
    r.hset('userinfo', i, '吉林乌拉')

print('Key为【userinfo】的字节编码为【%s】' % r.object('encoding', 'userinfo').decode('utf-8'))
Key为【userinfo】的字节编码为【ziplist】
Key为【userinfo】的字节编码为【hashtable】

Redis中的列表类型。在Redis中列表类型,可以简单的理解为存储多个有序字符串的一种新类型,这种类型除了字符串类型中已有的功能外,还提供了其它的功能。如可以对列表的两端插入和弹出元素(在列表中的字符串都可以称之为元素),除此之外还可以获取指定的元素列表,并且还可以通过索引下标获取指定元素等等。下面我们通过下图来看一下Redis中列表类型的插入和弹出操作:

img

下面我们看一下Redis中列表类型的获取与删除操作:

img

下面我们看一下Redis列表类型的特点:

  • 列表中所有的元素都是有序的。所以在Redis中列表类型是可以通过索引获取的,也就是上图中的
lindex命令


并且在Redis中列表类型的索引是从0开始的。

  • 列表中的元素是可以重复的。也就是说在Redis列表类型中,是可以保存重复的元素,也就是如下图所示:
img

下面我们还是和学习其它数据类型一样,我们还是先学习一下Redis列表类型的命令。

命令

一、添加操作

1.从右边插入元素

rpush key value [value ...]
img

我们看rpush命令在插入时,是有返回值的,返回值的数量就是当前列表中所有元素的个数。

我们也可以用下面的命令从左到右获取当前列表中的所有的元素,也就是如上图所示中那样。

lrange 0 -1 

2.从左边插入元素

lpush key value [value ...]
img

lpush命令的返回值及用法和rpush命令一样,这里就不在介绍了,但通过上面的事例证明了我们前面说的,因为当前key中已经有了3个元素了,所以我们在执行插入命令时,返回的就是6而不是3,因为rpush命令和lpush命令的返回值并不是当前插入元素的个数,而返回的是当前key中全部元素的个数。


3.向某个元素前或者后插入元素

linsert key BEFORE|AFTER pivot value
img

linsert命令在执行的时候首先会从当前列表中查找到pivot元素,其次在将这个新元素插入到pivot元素的前面或者后面。并且我们通过上图所示知道linsert命令在执行成功后也是会有返回值的,返回的结果就是当前列表中元素的个数。


二、查找

1.获取指定范围内的元素列表

lrange key start stop
img

lrange命令会获取列表中指定索引范围的所有元素。通过索引获取列表主要有两个特点:

  • 索引下标从左到右分别是0到N-1,从右到左是-1到-N。
  • lrange命令中的end参数在执行时会包括当前元素的。并不是所有的语言都是这样的。如我们要获取列表中前两个元素则可以如下图所示:

2.获取列表中指定索引下标的元素

lindex key index
img

3.获取列表长度

llen key
img

三、删除

1.从列表左侧弹出元素

lpop key
img

lpop命令执行成功后会返回当前被删除的元素名称。


2.从列表右侧弹出元素

rpop key
img

rpop命令和lpop命令的使用方式一样,这里不在做过多介绍了。


3.删除指定元素

lrem key count value


lrem命令会将列表中等于value的元素删除掉,并且会根据count参数,来决定删除value的元素个数。下面我们看一下count参数的使用说明:

  • count > 0:表示从左到右,最多删除count个元素。也就是如下图所示:

    我们看上图中的命令中,虽然我们将count参数指定的是5,将value参数指定的是2,但由于当前列表中只有一个2,所以,当前lrem命令最多只能删除1个元素,并且lrem命令也是有返回值的,也就是当前成功删除元素的个数。
  • count < 0:从右到左,最多删除count个元素。
  • count = 0:删除所有元素。

4.按照索引范围修剪列表

ltrim key start stop


ltrim命令会直接保留start索引到stop索引的之间的元素,并包括当前元素,而之外的元素则都会删除掉,所以该命令也叫修剪列表。

img

并且有一点要注意ltrim命令不会返回当前的列表中元素的个数,而是返回改命令是否成功的状态。


四、修改

1.修改指定索引下标的元素

lset key index value
img

五、阻塞操作

blpop key [key ...] timeout
brpop key [key ...] timeout


blpop和brpop命令是lpop和rpop命令的阻塞版本,它们除了弹出方向不同以外,使用方法基本相同。

  • key [key …]:可以指定多个列表的键。
  • timeout:阻塞时间(单位:秒)

下面我们看一下该命令的详细使用。

  1. 列表为空:如果timeout=3,则表示客户端等待3秒后才能返回结果,如果timeout=0,则表示客户端会一直等待,也就是会阻塞。

    由于我期间向列表中插入了元素,否则上述命令将一直阻塞下去。
    2.列表不为空:如果timeout=0,并且列表不为空时,则blpop和brpop命令会立即返回结果,不会阻塞。

下面我们看一下blpop和brpop命令的注意事项。

  • 如果使用blpop和brpop命令指定多个键时,blpop和brpop命令会从左到右遍历键,并且一旦有一个键能返回元素,则客户端会立即返回。

    当列表为空时,上述命令会阻塞,如果向上述中的任何一个键中插入元素,则上述命令会直接返回该键的元素。
  • 如果多个客户端都对同一个键执行blpop或者brpop命令,则最先执行该命令的客户端会获取到该键的元素。

    我同时启动了3个客户端,因为当前列表为空,所以上述命令执行后会阻塞。如果此时我向该列表中插入元素,则只有第一个客户端会有返回结果,因为第一个客户端是第一个执行上述命令的。


下面我们看一下列表中命令的相关时间复杂度。

操作类型命令时间复杂度
添加rpush key value [value …]O(k),k是元素的个数
添加lpush key value [value …]O(k),k是元素的个数
添加linsert key BEFORE/AFTER pivot valueO(n),n是pivot距离列表头或者尾的距离
添加lrange key start stopO(s + n),s是start偏移量,n是start到stop的范围
添加lindex key indexO(n),n是索引的偏移量
添加llen keyO(1)
添加lpop keyO(1)
添加rpop keyO(1)
添加lrem key count valueO(n),n是列表长度
添加ltrim key start stopO(n),n是要裁剪的元素个数
添加lset key index valueO(n),n是索引的偏移量
添加blpop/brpop key [key …] timeoutO(1)

内部编码

列表中的内部编码有两种,它们分别是:

  • ziplist(压缩列表):当列表中元素个数小于512(默认)个,并且列表中每个元素的值都小于64(默认)个字节。Redis会选择用ziplist来作为列表的内部实现来减少内存的使用。当然上述默认值也可以通过相关参数修改:list-max-ziplist-entried(元素个数)、list-max-ziplist-value(元素值)。
  • linkedlist(链表):当列表类型无法满足ziplist条件时,Redis会选择用linkedlist作为列表的内部实现。
    下面我们通过相关命令来验证上述所说。
img

1.当元素个数较少并且没有大元素时,内部编码为ziplist。

我们看当我们在列表中插入少量元素,并且没有大元素时,返回的内部编码并不是ziplist而是quicklist。这又是什么编码呢。简单来说,quicklist编码是Redis3.2版本之后(包括当前版本)提供了一种新的内部编码。它和ziplist和linkedlist编码相比它结合了这两种编码的优势,具体的区别以后的文章中在做详细介绍。由于我电脑安装的Redis的版本是4.0.9,在3.2版本之后所以,上述代码执行后的内部编码为quicklist。


2.当元素个数超过512个元素时,内部编码将变为linkedlist。以下代码都是本人在Redis4.0.9中的测试,所以上述的验证本人没有验证成功。

import redis

r = redis.Redis(host='127.0.0.1', port=6379)

print('Key为【listkey】的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))

for i in range(1,512):
    r.rpush('listkey', i)

print('Key为【listkey的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))
Key为【listkey】的字节编码为【quicklist】
Key为【listkey的字节编码为【quicklist】

3.当列表中某个元素超过64个字节时,内部编码也会变成linkedlist。以下代码也是本人在Redis4.0.9中的测试,所以上述的验证本人也没有验证成功。

import redis

r = redis.Redis(host='127.0.0.1', port=6379)

print('Key为【listkey】的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))

value = ''

for i in range(1,512):
    value += str(i)

r.rpush('listkey', i)

print('Key为【listkey的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))
Key为【listkey】的字节编码为【quicklist】
Key为【listkey的字节编码为【quicklist】

Redis中的集合类型,也就是set集合。在Redis中set也是可以保存多个字符串的。那么set集合和list链表到底有什么不同呢?下面我们重点介绍一下它们之间的不同。

  • set中的元素是不可以重复的,而list是可以保存重复元素的。
  • set中的元素是无序的,而list中的元素是有序的。
  • set中的元素不能通过索引下标获取元素,而list中的元素则可以通过索引下标获取元素。
  • 除此之外set还支持更高级的功能,例如多个set取交集、并集、差集、等等。

下面我们介绍一下set中的相关命令。


命令

一、集合内操作

1.添加元素

sadd key member [member ...]
img

sadd命令也是有返回值的,它的返回值就是当前执行sadd命令成功添加元素的个数,因为set中不能保存重复元素,所以在执行:

sadd setkey c d


命令时,返回的是1,而不是2。因为元素c,已经成功保存到set中,不在继续保存了,只能将d保存到set中。


2.删除元素

srem key member [member ...]
img

srem命令和sadd命令一样也是有返回值的,返回值就是当前删除元素的个数。


3.计算元素个数

scard key
img

scard命令的时间复杂度为O(1),scard命令不会遍历set中的所有元素,而是直接使用Redis中的内部变量。


4.判读元素是否在集合中

sismember key member
img

sismember命令也有返回值,如果返回值为1则表示当前元素在当前set中,如果返回0则表示当前元素不在set中。


5.随机从set中返回指定个数元素

srandmember key [count]
img

srandmember命令中有一个可选参数count,count参数指的是返回元素的个数,如果当前set中的元素个数小于count,则srandmember命令返回当前set中的所有元素,如果count参数等于0,则不返回任何数据,如果count参数小于0,则随机返回当前count个数的元素,不管当前set中的元素个数为多少。


6.从集合中随机弹出元素

spop key [count]
img

spop命令也是随机从set中弹出元素,并且也支持count可选参数,但有一点和srandmember命令不同。spop命令在随机弹出元素之后,会将弹出的元素从set中删除,而srandmember命令则不同,只会随机弹出元素,并不会将元素从set中删除。


7.获取所有元素

smembers key
img

smembers命令虽然能获取当前set中所有的元素,但smembers命令返回元素的顺序与sadd添加元素的顺序不一定相同,这也就是前面提到过的保存在set中的元素是无序的。


二、集合间操作

1.集合的交集

sinter key [key ...]
img

2.集合的并集

sunion key [key ...]
img

3.集合的差集

sdiff key [key ...]
img

4.将集合的交集、并集、差集的结果保存

sinterstore destination key [key ...]
sunionstore destination key [key ...]
sdiffstore destination key [key ...]
img

为什么Redis要提供了sinterstore、sunionstore、sdiffstore命令来将集合的交集、并集、差集的结果保存起来呢?这是因为Redis在进行上述比较时,会比较耗费时间,所以为了提高性能可以将交集、并集、差集的结果提前保存时来,这样在需要使用时,可以直接通过smembers命令获取。


下面我们看一下set中相关命令的时间复杂度。

命令时间复杂度
sadd key member [member …]O(k),k是元素的个数
srem key member [member …]O(k),k是元素的个数
scard keyO(1)
sismember key memberO(1)
srandmember key [count]O(count)
spop key [count]O(1)
smembers keyO(n),n是元素的总数
sinter key [key …]O(m * k),k是多个集合中元素最少的个数,m是键个数
sunion key [key …]O(k),k是多个元素个数和
sdiff key [key …]O(k),k是多个元素个数和
sinterstore destination key [key …]O(m * k),k是多个集合中元素最少的个数,m是键个数
sunionstore destination key [key …]O(k),k是多个元素个数和
sdiffstore destination key [key …]O(k),k是多个元素个数和

内部编码

  • intset(整数集合):当集合中的元素都是整数,并且集合中的元素个数小于512个时,Redis会选用intset作为底层内部实现。
  • hashtable(哈希表):当条件不满足上述时,Redis会采用hashtable作为底层实现。

备注:我们可以通过set-max-intset-entries参数来设置上述中的默认参数。


下面我们看一下具体的事例,来验证我们上面提到的内部编码。

img

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


img

2.当元素不全是整数时,内部编码为hashtable。


3.当元素个数超过512个时,内部编码为hashtable。

import redis

r = redis.Redis(host='127.0.0.1', port=6379)

if r.object('encoding', 'setkey') != None:
    print('Key为【setkey】的字节编码为【%s】' % r.object('encoding', 'setkey').decode('utf-8'))

for i in range(1, 600):
    r.sadd('setkey', i)

if r.object('encoding', 'setkey') != None:
    print('Key为【setkey】的字节编码为【%s】' % r.object('encoding', 'setkey').decode('utf-8'))
Key为【setkey】的字节编码为【intset】
Key为【setkey】的字节编码为【hashtable】

有序集合类型,也是Redis中的5大数据类型中的最后一个。看名字,我们就知道,有序集合也是一种集合,并且这个集合还是有序的。那有序集合和列表有什么不同呢?因为列表也是有序的。 它们到底有什么不同呢?有序集合的有序和列表的有序是不同的。列表中的有序指的的是插入元素的顺序,和查询元素的顺序相同。而有序集合中的有序指的是它会为每个元素设置一个分数(score),而查询时可以通过分数计算元素的排名,然后在返回结果。因为有序集合也是集合类型,所以有序集合中也是不插入重复元素的,但在有序集合中分数则是可以重复,那如果在有序集合中有多个元素的分数是相同的,那么这些重复的元素的排名是怎么计算的呢?在下面的内容中我们在做详细说明。下面我们看一下列表、集合、有序集合的它们3个数据类型之间的区别。

数据结构是否允许重复元素是否有序有序实现方式应用场景
列表索引下标时间轴、消息队列
集合否标签、社交
有序集合否分数排行榜、社交

下面我们重点了解一下Redis中有序集合的相关命令。

命令

一、集合内

1.添加元素

zadd key [NX|XX] [CH] [INCR] score member [score member ...]
img

zadd命令也是有返回值的,返回值就是当前zadd命令成功添加元素的个数。除此之外,zadd命令还有很多其它的选填参数。下面我们详细了解一下:

  • nx: 元素必须不存在时,才可以设置成功。
  • xx: 元素必须存在时,才可以设置成功。
  • ch:
  • incr: 对score做增加。

备注:由于有序集合相比集合提供了排序字段,正是因为如此也付出了相应的代价,,zadd的时间复杂度为O(log(n)),sadd的时间复杂度为O(1)。


2.计算成员个数

zcard key
img

3.计算某个成员的分数

zscore key member
img

在使用zscore命令时,如果key不存在,或者元素不存在时,该命令返回的都是(nil)。


4.计算成员的排名

zrank key member
zrevrank key member
img

zrank命令是从分数低到高排名,而zrevrank命令则恰恰相反,从高到低排名。有一点要特别注意zrank和zrevrank命令与zscore命令不同的前者是通过分数计算出最后的排名,而后者则是直接返回当前元素的分数。


5.删除元素

zrem key member [member ...]
img

返回的结果为成功删除元素的个数,因为zrem命令是支持批量删除的。


6.增加元素分数

zincrby key increment member
img

虽然zincrby命令是增加元素分数的,但我们也可以指定负数,这样当前元素的分数,则会相减。


7.返回指定排名范围的元素

zrange key start stop [WITHSCORES]
zrevrange key start stop [WITHSCORES]
img

zrange命令是通过分数从低到高返回数据,而zrevrange命令是通过分数从高到低返回数据。如果执行命令时如果添加了WITHSCORES可选参数,而返回数据时会返回当前元素的分数。


8.返回指定分数范围的元素

zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
zrevrangebyscore key max min [WITHSCORES] [LIMIT offset count]
img

min和max参数同时还支持开区间(小括号)和闭区间(中括号),同时我们还可以用-inf和+inf参数代表无限小和无限大。

img

备注:闭区间的没有验证成功,执行时会报错,这个有待验证。


9.返回指定分数范围元素个数

zcount key min max
img

10.删除指定指定排名内的升序元素

zremrangebyrank key start stop
img

11.删除指定分数范围元素

zremrangebyscore key min max
img

二、集合间操作

1.交集

zinterstore destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]


因为zinterstore命令参数比较多,所以下面我们详细了解一下:

  • destination:将交集的计算结果,保存到这个键中。
  • numkeys:需要做交集计算键的个数。
  • key [key …]:需要做交集计算的键。
  • WEIGHTS weight:每个键的权重,在做交集计算时,每个键中的分数值都会乘以这个权重,默认每个键的权重为1。
  • AGGREGATE SUM|MIN|MAX:计算成员交集后,分值可以按照sum(和)、min(最小值)、max(最大值)做汇总,默认值为sum。

    下面我们将权重设置为0.5,这样当计算交集后,有序集合中的元素分数将都会减半,并且使用max参数汇总。

2.并集

zunionstore destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
img

zunionstore命令的相关参数和zinterstore命令相同。


时间复杂度

下面我们了解一下上述命令的时间复杂度。

命令时间复杂度
zadd key [NX/XX] [CH] [INCR] score member [score member …]O(k*log(n)),k是添加元素的个数,n是当前有序集合元素个数
zcard keyO(1)
zscore key memberO(1)
zrank key memberO(log(n)),n是当前有序集合元素个数
zrevrank key memberO(log(n)),n是当前有序集合元素个数
zrem key member [member …]O(k*log(n)),k是删除元素的个数,n是当前有序集合元素个数
zincrby key increment memberO(log(n)),n是当前有序集合元素个数
zrange key start stop [WITHSCORES]O(log(n) + k),k是要获取的元素个数,n是当前有序集合个数
zrevrange key start stop [WITHSCORES]O(log(n) + k),k是要获取的元素个数,n是当前有序集合个数
zrangebyscore key min max [WITHSCORES] [LIMIT offset count]O(log(n) + k),k是要获取的元素个数,n是当前有序集合个数
zrevrangebyscore key max min [WITHSCORES] [LIMIT offset count]O(log(n) + k),k是要获取的元素个数,n是当前有序集合个数
zcount key min maxO(log(n)),n是当前有序集合元素个数
zremrangebyrank key start stopO(log(n) + k),k是要删除的元素个数,n是当前有序集合个数
zremrangebyscore key min maxO(log(n) + k),k是要删除的元素个数,n是当前有序集合个数
zinterstore destination numkeys key [key …] [WEIGHTS weight] [AGGREGATE SUM/MIN/MAX]O(n * k) + O(m * log(m)),n是元素元素最小的有序集合元素个数,k是有序集合个数,m是结果集中元素个数
zunionstore destination numkeys key [key …] [WEIGHTS weight] [AGGREGATE SUM/MIN/MAX]O(n) + O(m * log(m)),n是所有有序集合元素个数和,m是结果集中元素个数。

内部编码

有序集合类型的内部编码有两种,它们分别是:

  • ziplist(压缩列表):当有序集合的元素个数小于128个(默认设置),同时每个元素的值都小于64字节(默认设置),Redis会采用ziplist作为有序集合的内部实现。
  • skiplist(跳跃表):当上述条件不满足时,Redis会采用skiplist作为内部编码。

备注:上述中的默认值,也可以通过以下参数设置:zset-max-ziplist-entries和zset-max-ziplist-value。


下面我们用以下示例来验证上述结论。

1.当元素个数比较少,并且每个元素也比较小时,内部编码为ziplist:

img

2.当元素个数超过128时,内部编码为skiplist。下面我们将采用python动态创建128个元素,下面为源码:

import redis

r = redis.Redis(host='127.0.0.1', port=6379)

if r.object('encoding', 'zsetkey') != None:
    print('Key为【zsetkey】的字节编码为【%s】' % r.object('encoding', 'zsetkey').decode('utf-8'))

for i in range(1, 600):
    r.zadd('zsetkey',i,1)

if r.object('encoding', 'zsetkey') != None:
    print('Key为【zsetkey】的字节编码为【%s】' % r.object('encoding', 'zsetkey').decode('utf-8'))
Key为【zsetkey】的字节编码为【ziplist】
Key为【zsetkey】的字节编码为【skiplist】

3.当有序集合中有任何一个元素大于64个字节时,内部编码为skiplist。

import redis

r = redis.Redis(host='127.0.0.1', port=6379)

if r.object('encoding', 'zsetkey') != None:
    print('Key为【zsetkey】的字节编码为【%s】' % r.object('encoding', 'zsetkey').decode('utf-8'))

value = ''
for i in range(1, 600):
    value += str(i)

r.zadd('zsetkey',value,1)

if r.object('encoding', 'zsetkey') != None:
    print('Key为【zsetkey】的字节编码为【%s】' % r.object('encoding', 'zsetkey').decode('utf-8'))
Key为【zsetkey】的字节编码为【skiplist】
img

上述内容就是Redis中5种数据类型的内容,如有不正确的地方,欢迎留言,谢谢。

原创文章,作者:二十四分之七倍根号六,如若转载,请注明出处:http://jilinwula.com/449.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注

联系我们

邮件:admin@jilinwula.com

QQ:923505769

 

QR code