【Redis学习】Redis常用数据类型的万字详解
Redis学习笔记:
https://blog.csdn.net/2301_80220607/category_13051025.html?spm=1001.2014.3001.5482
前言:
上一篇已经讲解了Redis中String字符串类型的许多指令的使用,Redis中这些数据类型的相关指令都是十分相似的,今天我们将除了String以外的剩下的几个Redis常用数据类型及其相关知识点讲解一下
目录
一、Hash(哈希)
1. 命令
1.1 HSET
1.2 HGET
1.3 HEXISTS
1.4 HDEL
1.5 HKEYS
1.6 HVALS
1.7 HGETALL
1.8 HMGET
1.9 HLEN
1.10 HSETNX
1.11 HINCRBY
1.12 HINCRBYFLOAT
2. 命令小结
3.内部编码
二、List(列表)
1. 命令
1.1 LPUSH
1.2 LPUSHX
1.3 RPUSH
1.4 RPUSHX
1.5 LRANGE
1.6 LPOP
1.7 RPOP
1.8 LINDEX
1.9 LINSERT
1.10 LLEN
2. 阻塞版本命令
2.1 BLPOP
2.2 BRPOP
3. 内部编码
三、Set(集合)
1. 普通命令
1.1 SADD
1.2 SMEMBERS
1.3 SISMEMBER
1.4 SCARD
1.5 SPOP
1.6 SMOVE
1.7 SREM
2. 集合间操作
2.1 SINTER
2.2 SINTERSTORE
2.3 SUNION
2.4 SUNIONSTORE
2.5 SDIFF
2.6 SDIFFSTORE
四、Zset(有序集合)
1. 普通命令
1.1 ZADD
1.2 ZCARD
1.3 ZCOUNT
1.4 ZRANGE
1.5 ZREVRANGE
1.6 ZRANGEBYSCORE
1.7 ZPOPMAX
1.8 ZPOPMIN
1.9 BZPOPMIN
1.10 ZRANK
1.11 ZSCORE
1.12 ZREM
1.13 ZREMRANGEBYRANK
1.14 ZREMRANGEBYSCORE
1.15 ZINCRBY
2. 集合间操作
2.1 ZINTERSTORE
2.2 ZUNIONSTORE
3. 内部编码
五、总结
一、Hash(哈希)
几乎所有的主流编程语言都支持哈希结构,在不同的编程语言中它可能有不同的叫法:哈希、字典序、映射......我们的Redis也支持哈希这种数据类型,一个有意思的点是:Redis本身的整体数据结构就是以key-value的哈希的结构存在的,这就相当于是哈希中嵌套哈希:key-(key-value),非常有意思,为了避免混淆,我们可以把第二个key改一下:key-(field-value)
1. 命令
1.1 HSET
设置哈希中指定的字段(field)的值(value)
HSET key field value [field value ...]
- 时间复杂度:插⼊⼀组 field 为 O(1), 插⼊ N 组 field 为 O(N)
- 返回值:添加的字段的个数。
示例:
127.0.0.1:6379> hset myhash field "hello"
(integer) 1
127.0.0.1:6379> hget myhash field
"hello"
1.2 HGET
获取hash中指定字段的值
HGET key field
- 时间复杂度:O(1)
- 返回值:字段对应的值或者 nil。
127.0.0.1:6379> hset myhash field "hello"
(integer) 1
127.0.0.1:6379> hget myhash field
"hello"
127.0.0.1:6379> hget myhash field2
(nil)
1.3 HEXISTS
判断hash中是否有指定的字段
HEXISTS key field
- 时间复杂度:O(1)
- 返回值:1 表⽰存在,0 表⽰不存在。
127.0.0.1:6379> hset myhash field1 hello
(integer) 1
127.0.0.1:6379> hexists myhash field1
(integer) 1
127.0.0.1:6379> hexists myhash field2
(integer) 0
1.4 HDEL
删除hash中指定的字段
HDEL key field [field ...]
- 时间复杂度:删除⼀个元素为 O(1). 删除 N 个元素为 O(N).
- 返回值:本次操作删除的字段个数。
127.0.0.1:6379> hdel myhash field
(integer) 1
127.0.0.1:6379> hdel myhash field1 field2
(integer) 1
1.5 HKEYS
获取hash中的所有字段
HKEYS key
- 时间复杂度:O(N), N 为 field 的个数.
- 返回值:字段列表。
127.0.0.1:6379> hset myhash field1 hello
(integer) 1
127.0.0.1:6379> hset myhash field2 world
(integer) 1
127.0.0.1:6379> hkeys myhash
1) "field1"
2) "field2"
1.6 HVALS
获取哈希中的所有值
HVALS key
- 时间复杂度:O(N), N 为 field 的个数.
- 返回值:所有的值。
127.0.0.1:6379> hset myhash field1 hello
(integer) 1
127.0.0.1:6379> hset myhash field2 world
(integer) 1
127.0.0.1:6379> hvals myhash
1) "hello"
2) "world"
1.7 HGETALL
获取hash中所有字段以及对应的值
HGETALL key
- 时间复杂度:O(N), N 为 field 的个数.
- 返回值:字段和对应的值。
127.0.0.1:6379> hset myhash field1 hello
(integer) 1
127.0.0.1:6379> hset myhash field2 world
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hello"
3) "field2"
4) "world"
1.8 HMGET
一次性获取hash中多个字段的值
HMGET key field [field ...]
- 时间复杂度:只查询⼀个元素为 O(1), 查询多个元素为 O(N), N 为查询元素个数.
- 返回值:字段对应的值或者 nil。
127.0.0.1:6379> hset myhash field1 hello
(integer) 1
127.0.0.1:6379> hset myhash field2 world
(integer) 1
127.0.0.1:6379> hmget myhash field1 field2 nofield
1) "hello"
2) "world"
3) (nil)
注意:在使用上面的HGETALL时,如果hash中元素过多,可能会造成阻塞Redis的情况,如非必要尽量不要选择查看所有的元素,而是通过HMGET来获取指定的元素,如果一定要获取全部的元素时,可以采用我们下面将要讲的HSCAN的分批次进行获取
1.9 HLEN
获取hash中所有字段的个数
HLEN key
- 时间复杂度:O(1)
- 返回值:字段个数。
127.0.0.1:6379> hset myhash field1 hello
(integer) 1
127.0.0.1:6379> hset myhash field2 world
(integer) 1
127.0.0.1:6379> hlen myhash
(integer) 2
1.10 HSETNX
在字段不存在的情况下,设置字段以及对应的值
HSETNX key field value
- 时间复杂度:O(1)
- 返回值:1 表⽰设置成功,0 表⽰失败。
127.0.0.1:6379> hsetnx myhash field1 hello
(integer) 1
127.0.0.1:6379> hsetnx myhash field1 world
(integer) 0
127.0.0.1:6379> hget myhash field1
"hello"
1.11 HINCRBY
将hash中指定字段的数值添加上指定的值
HINCRBY key field increment
- 时间复杂度:O(1)
- 返回值:该字段变化之后的值。
127.0.0.1:6379> hset myhash field 1
(integer) 1
127.0.0.1:6379> hincrby myhash field 10
(integer) 11
127.0.0.1:6379> hincrby myhash field -10
1.12 HINCRBYFLOAT
HINCRBY的FLOAT版本
HINCRBYFLOAT key field increment
- 时间复杂度:O(1)
- 返回值:该字段变化之后的值
2. 命令小结
命令 | 执⾏效果 | 时间复杂度 |
---|---|---|
hset key field value | 设置值 | O(1) |
hget key field | 获取值 | O(1) |
hdel key field [field ...] | 删除 field | O(k), k 是 field 个数 |
hlen key | 计算 field 个数 | O(1) |
hgetall key | 获取所有的 field-value | O(k), k 是 field 个数 |
hmget field [field ...] | 批量获取 field-value | O(k), k 是 field 个数 |
hmset field value [field value ... | 批量设置 field-value | O(k), k 是 field 个数 |
hexists key field | 判断 field 是否存在 | O(1) |
hkeys key | 获取所有的 field | O(k), k 是 field 个数 |
hvals key | 获取所有的 value | O(k), k 是 field 个数 |
hsetnx key field value | 设置值,但必须在 field 不存在时才能设置成功 | O(1) |
hincrby key field n | 对应 field-value +n | O(1) |
hincrbyfloat key field n | 对应 field-value +n | O(1) |
hstrlen key field | 计算 value 的字符串⻓度 | O(1) |
3.内部编码
- ziplist(压缩列表):当哈希类型元素个数⼩于 hash-max-ziplist-entries 配置(默认 512 个)、同时所有值都⼩于 hash-max-ziplist-value 配置(默认 64 字节)时,Redis 会使⽤ ziplist 作为哈希的内部实现,ziplist 使⽤更加紧凑的结构实现多个元素的连续存储,所以在节省内存⽅⾯⽐hashtable 更加优秀。
- hashtable(哈希表):当哈希类型⽆法满⾜ ziplist 的条件时,Redis 会使⽤ hashtable 作为哈希的内部实现,因为此时 ziplist 的读写效率会下降,⽽ hashtable 的读写时间复杂度为 O(1)。
下面来看一下哈希内部的编码,以及响应类型的变换:
当field个数比较少,且内部的值不是很大时,内部编码为ziplist:
127.0.0.1:6379> hmset myhash f1 v1 f2 v2
OK
127.0.0.1:6379> object encoding myhash
"ziplist"
当有value大于64字节时,内部编码会转变为hashtable:
127.0.0.1:6379> hmset myhash f3 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
OK
127.0.0.1:6379> object encoding myhash
"hashtable"
当field个数超过512个时,内部编码也会转化为hashtable:
127.0.0.1:6379> hmset hashkey f1 v1 h2 v2 f3 v3 ... 省略 ... f513 v513
OK
127.0.0.1:6379> object encoding hashkey
"hashtable"
二、List(列表)
列表类型是用来存储多个字符串,如图,a、b、c、d、e五个元素从左到右组成一个有序的列表,列表中每个字符串被称为一个元素,,一个列表最多有2^32-1个元素。在Redis中,列表可以进行两端插入取出,获取指定范围内的元素,获取指定下标的元素等操作,总之列表是Redis中一种十分好用的数据机构,在很多场景下都能够得到使用
1. 命令
1.1 LPUSH
将一个或多个元素头插到列表中
LPUSH key element [element ...]
- 时间复杂度:只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.
- 返回值:插⼊后 list 的⻓度。
示例:
127.0.0.1:6379> lpush mylist hello
(integer) 1
127.0.0.1:6379> lpush mylist world
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "world"
2) "hello"
1.2 LPUSHX
当key存在时,将一个或多个元素头插到列表中
LPUSHX key element [element ...]
- 时间复杂度:只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.
- 返回值:插⼊后 list 的⻓度。
127.0.0.1:6379> lpush mylist hello
(integer) 1
127.0.0.1:6379> lpushx mylist world
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "world"
2) "hello"
127.0.0.1:6379> lpushx mylist2 hello
(integer) 0
127.0.0.1:6379> lrange mylist2 0 -1
1.3 RPUSH
将一个或多个元素尾插到列表中
RPUSH key element [element ...]
- 时间复杂度:只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.
- 返回值:插⼊后 list 的⻓度。
127.0.0.1:6379> rpush mylist hello
(integer) 1
127.0.0.1:6379> rpush mylist world
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
1.4 RPUSHX
当key存在的时候,将一个或多个元素尾插到列表中
RPUSHX key element [element ...]
- 时间复杂度:只插⼊⼀个元素为 O(1), 插⼊多个元素为 O(N), N 为插⼊元素个数.
- 返回值:插⼊后 list 的⻓度。
示例:
127.0.0.1:6379> rpush mylist hello
(integer) 1
127.0.0.1:6379> rpushx mylist world
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
127.0.0.1:6379> rpushx mylist2 hello
(integer) 0
127.0.0.1:6379> lrange mylist2 0 -1
(empty list or set)
1.5 LRANGE
获取从start到end之间的所有元素,左闭右闭
LRANGE key start stop
- 时间复杂度:O(N)
- 返回值:指定区间的元素。
127.0.0.1:6379> rpush mylist hello
(integer) 1
127.0.0.1:6379> rpush mylist world
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
1.6 LPOP
头删
LPOP key
- 时间复杂度:O(1)
- 返回值:取出的元素或者 nil。
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
127.0.0.1:6379> lpop mylist
"hello"
127.0.0.1:6379> lrange mylist 0 -1
1) "world"
1.7 RPOP
尾删
RPOP key
- 时间复杂度:O(1)
- 返回值:取出的元素或者 nil。
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
127.0.0.1:6379> rpop mylist
"world"
127.0.0.1:6379> lrange mylist 0 -1
1.8 LINDEX
获取从左数第index位置的元素
LINDEX key index
- 时间复杂度:O(N)
- 返回值:取出的元素或者 nil。
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
127.0.0.1:6379> lindex mylist 0
"hello"
127.0.0.1:6379> lindex mylist -1
"world"
127.0.0.1:6379> lindex mylist 2
1.9 LINSERT
在特定位置插入元素
LINSERT key <BEFORE | AFTER> pivot element
- 时间复杂度:O(N)
- 返回值:插⼊后的 list ⻓度。
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
127.0.0.1:6379> linsert mylist before world one
(integer) 3
127.0.0.1:6379> linsert mylist after world two
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "one"
3) "world"
4) "two"
1.10 LLEN
获取列表长度
LLEN key
- 时间复杂度:O(1)
- 返回值:list 的⻓度。
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "one"
3) "world"
4) "two"
127.0.0.1:6379> llen mylist
(integer) 4
2. 阻塞版本命令
blpop和brpop是lpop和rpop的阻塞版本。两者用法很相似,但也有些不同之处:
- 在列表中有元素的情况下,阻塞和⾮阻塞表现是⼀致的。但如果列表中没有元素,⾮阻塞版本会理 解返回 nil,但阻塞版本会根据 timeout,阻塞⼀段时间,期间 Redis 可以执⾏其他命令,但要求执⾏该命令的客⼾端会表现为阻塞状态
- 命令中如果设置了多个键,那么会从左向右进⾏遍历键,⼀旦有⼀个键对应的列表中可以弹出元素,命令⽴即返回
- 如果多个客⼾端同时多⼀个键执⾏ pop,则最先执⾏命令的客⼾端会得到弹出的元素
2.1 BLPOP
LPOP的阻塞版本
BLPOP key [key ...] timeout
- 时间复杂度:O(1)
- 返回值:取出的元素或者 nil。
我们看这个命令的语法,它与LPOP主要有两处不同,一是它能同时监视多个key,二是它需要设置一个超时时间,当我们设置一个超时时间后,比如5s,那么在5s内,我们所监视的key里面哪个最先有值我们就头删掉,当头删成功或者超时时,命令就会被结束掉
我们开启两个redis客户端来测试一下,其中一个redis客户端监视多个里面为空的key,另一个客户端向其中一个空值key里面插入一个数据,然后观察命令的执行情况:
当未插入时:
如图,当我们监视的key在指定时间内一直为空时,超时后就会返回空,如果在这个时间内插入数据就会返回插入的值
当插入时:
2.2 BRPOP
RPOP的阻塞版本
BRPOP key [key ...] timeout
- 时间复杂度:O(1)
- 返回值:取出的元素或者 nil。
用法方面跟上面的BLPOP同理,这里就不赘述了
3. 内部编码
列表类型的内部编码有两种:
- ziplist(压缩列表):当列表的元素个数⼩于 list-max-ziplist-entries 配置(默认 512 个),同时列表中每个元素的⻓度都⼩于 list-max-ziplist-value 配置(默认 64 字节)时,Redis 会选⽤ ziplist 来作为列表的内部编码实现来减少内存消耗。
- linkedlist(链表):当列表类型⽆法满⾜ ziplist 的条件时,Redis 会使⽤ linkedlist 作为列表的内部实现。
当元素个数较少,且没有大元素时,内部编码为ziplist:
127.0.0.1:6379> rpush listkey e1 e2 e3
OK
127.0.0.1:6379> object encoding listkey
"ziplist"
当元素个数超过512时,内部编码为linkedlist:
127.0.0.1:6379> rpush listkey e1 e2 e3 ... 省略 e512 e513
OK
127.0.0.1:6379> object encoding listkey
"linkedlist"
当某个元素长度超过64字节时,内部编码为linkedlist:
127.0.0.1:6379> rpush listkey "one string is bigger than 64 bytes ... 省略 ..."
OK
127.0.0.1:6379> object encoding listkey
"linkedlist"
三、Set(集合)
集合也是保存多个字符串的类型,但是与列表不同的是,集合内部的元素是无序的,且不能重复,一个集合中最多可以有2^32-1个元素。Redis除了支持集合内部的增删查改,还支持集合间的求交集、并集和差集
1. 普通命令
1.1 SADD
将一个或多个元素添加到set中(不能重复)
SADD key member [member ...]
- 时间复杂度:O(1)
- 返回值:本次添加成功的元素个数。
127.0.0.1:6379> sadd myset "hello" "world" "world"
(integer) 2
127.0.0.1:6379> smembers myset
1) "world"
2) "hello"
1.2 SMEMBERS
获取一个列表中的所有元素(无序的)
SMEMBERS key
- 时间复杂度:O(N)
- 返回值:所有元素的列表。
127.0.0.1:6379> sadd myset "hello" "world" "world"
(integer) 2
127.0.0.1:6379> smembers myset
1) "world"
2) "hello"
1.3 SISMEMBER
判断一个元素在不在set中
SISMEMBER key member
- 时间复杂度:O(1)
- 返回值:1 表⽰元素在 set 中。0 表⽰元素不在 set 中或者 key 不存在。
127.0.0.1:6379> sadd myset one
(integer) 1
127.0.0.1:6379> sismember myset one
(integer) 1
127.0.0.1:6379> sismember myset two
(integer) 0
1.4 SCARD
获取一个set中的元素个数
SCARD key
- 时间复杂度:O(1)
- 返回值:set 内的元素个数。
127.0.0.1:6379> sadd myset one
(integer) 1
127.0.0.1:6379> scard myset
(integer) 1
1.5 SPOP
从set中随机删除指定个数的元素。
SPOP key [count]
- 时间复杂度:O(N), n 是 count
- 返回值:取出的元素。
127.0.0.1:6379> sadd myset one two three
(integer) 3
127.0.0.1:6379> smembers myset
1) "two"
2) "one"
3) "three"
127.0.0.1:6379> spop myset 1
1) "three"
127.0.0.1:6379> smembers myset
1) "two"
2) "one"
1.6 SMOVE
将一个元素从源set转入目标set
SMOVE source destination member
- 时间复杂度:O(1)
- 返回值:1 表⽰移动成功,0 表⽰失败。
127.0.0.1:6379> smembers myset
1) "two"
2) "one"
127.0.0.1:6379> smove myset myset2 one
(integer) 1
127.0.0.1:6379> smembers myset
1) "two"
127.0.0.1:6379> smembers myset2
1) "one"
1.7 SREM
将指定元素从set中删除
SREM key member [member ...]
- 时间复杂度:O(N), N 是要删除的元素个数.
- 返回值:本次操作删除的元素个数。
127.0.0.1:6379> smembers myset
1) "one"
2) "two"
127.0.0.1:6379> srem myset one two three
(integer) 2
127.0.0.1:6379> smembers myset
(empty list or set)
2. 集合间操作
集合间操作主要是指求交集、并集和差集
2.1 SINTER
获取给定set的交集中的元素
SINTER key [key ...]
127.0.0.1:6379> sadd myset1 a b c d e f
(integer) 6
127.0.0.1:6379> sadd myset2 a c f h i
(integer) 5
127.0.0.1:6379> sinter myset1 myset2
1) "a"
2) "f"
3) "c"
2.2 SINTERSTORE
获取给定的两个set的交集并将结果保存到给定的set中
SINTERSTORE destination key [key ...]
- 时间复杂度:O(N * M), N 是最⼩的集合元素个数. M 是最⼤的集合元素个数.
- 返回值:交集的元素个数。
127.0.0.1:6379> sadd myset1 a b c d e f
(integer) 6
127.0.0.1:6379> sadd myset2 a c f h i
(integer) 5
127.0.0.1:6379> sinter myset1 myset2
1) "a"
2) "f"
3) "c"
127.0.0.1:6379> sinterstore myret myset1 myset2
(integer) 3
127.0.0.1:6379> smembers myret
1) "a"
2) "f"
3) "c"
2.3 SUNION
获取给定set并集中的元素
SUNION key [key ...]
- 时间复杂度:O(N), N 给定的所有集合的总的元素个数.
- 返回值:并集的元素。
127.0.0.1:6379> sadd myset1 a b c d e f
(integer) 6
127.0.0.1:6379> sadd myset2 a c f h i
(integer) 5
127.0.0.1:6379> sunion myset1 myset2
1) "d"
2) "c"
3) "a"
4) "i"
5) "h"
6) "b"
7) "f"
8) "e"
2.4 SUNIONSTORE
获取给定set并集中的元素并保存到目标的set中
SUNIONSTORE destination key [key ...]
- 时间复杂度:O(N), N 给定的所有集合的总的元素个数.
- 返回值:并集的元素个数。
127.0.0.1:6379> sadd myset1 a b c d e f
(integer) 6
127.0.0.1:6379> sadd myset2 a c f h i
(integer) 5
127.0.0.1:6379> sunion myset1 myset2
1) "d"
2) "c"
3) "a"
4) "i"
5) "h"
6) "b"
7) "f"
8) "e"
127.0.0.1:6379> sunionstore myret myset1 myset2
(integer) 8
127.0.0.1:6379> smembers myret
1) "d"
2) "c"
3) "a"
4) "i"
5) "h"
6) "b"
7) "f"
8) "e"
2.5 SDIFF
获取给定set的差集中的元素
SDIFF key [key ...]
- 时间复杂度:O(N), N 给定的所有集合的总的元素个数.
- 返回值:差集的元素。
127.0.0.1:6379> sadd myset1 a b c d e f
(integer) 6
127.0.0.1:6379> sadd myset2 a c f h i
(integer) 5
127.0.0.1:6379> sdiff myset1 myset2
1) "b"
2) "d"
3) "e"
2.6 SDIFFSTORE
获取给定set的差集中的元素并存储到指定的set中
SDIFFSTORE destination key [key ...]
- 时间复杂度:O(N), N 给定的所有集合的总的元素个数.
- 返回值:差集的元素个数。
127.0.0.1:6379> sadd myset1 a b c d e f
(integer) 6
127.0.0.1:6379> sadd myset2 a c f h i
(integer) 5
127.0.0.1:6379> sdiffstore myret myset1 myset2
(integer) 3
127.0.0.1:6379> smembers myret
1) "b"
2) "d"
3) "e"
3. 内部编码
集合类型的内部编码有两种:
- intset(整数集合):当集合中的元素都是整数并且元素的个数⼩于 set-max-intset-entries 配置(默认 512 个)时,Redis 会选⽤ intset 来作为集合的内部实现,从⽽减少内存的使⽤。
- hashtable(哈希):当集合类型⽆法满⾜ intset 的条件时,Redis 会使⽤ hashtable 作为集合 的内部实现。
当元素个数较少且都为整数时,内部编码为intset:
127.0.0.1:6379> sadd setkey 1 2 3
(integer) 3
127.0.0.1:6379> object encoding setkey
"intset"
当元素个数多于512个时,内部编码为hashtable:
127.0.0.1:6379> sadd setkey 1 2 3 4
(integer) 513
127.0.0.1:6379> object encoding setkey
"hashtable
当元素中有非整数类型时,内部编码为hashtable:
127.0.0.1:6379> sadd setkey 1 2 3
(integer) 3
127.0.0.1:6379> object encoding setkey
"intset"
127.0.0.1:6379> sadd setkey hello
(integer) 1
127.0.0.1:6379> object encoding setkey
"hashtable"
四、Zset(有序集合)
有序集合和集合一样,都不能有重复元素,它于集合最大的区别就是它是有序,它是每个元素关联一个分数(score)的方式来确保有序
有序集合提供了获取指定分数和元素范围查找、计算成员排名等功能
1. 普通命令
1.1 ZADD
添加或更新指定的元素及分数到zset中,分数应该符合double类型,+inf/-inf作为正负极限也是合法的
ZADD相关选项:
- XX:仅仅⽤于更新已经存在的元素,不会添加新元素。
- NX:仅⽤于添加新元素,不会更新已经存在的元素。
- CH:默认情况下,ZADD 返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次更新的元素的个数。
- INCR:此时命令类似 ZINCRBY 的效果,将元素的分数加上指定的分数。此时只能指定⼀个元素和分数。
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member...]
- 时间复杂度:O(log(N))
- 返回值:本次添加成功的元素个数。
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
127.0.0.1:6379> zadd myzset 10 one
(integer) 0
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "two"
2) "2"
3) "three"
4) "3"
5) "one"
6) "10"
127.0.0.1:6379> zadd myzset ch 20 two 30 three
(integer) 2
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "one"
2) "10"
3) "two"
4) "20"
5) "three"
6) "30"
1.2 ZCARD
获取一个zset的基数,即zset中的元素个数
ZCARD key
- 时间复杂度:O(1)
- 返回值:zset 内的元素个数。
127.0.0.1:6379> zrange myzset 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> zcard myzset
(integer) 3
1.3 ZCOUNT
返回分数在min和max之间的元素的个数,默认情况下min和max都是包含的,可以通过( 排除
ZCOUNT key min max
- 时间复杂度:O(log(N))
- 返回值:满⾜条件的元素列表个数。
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
127.0.0.1:6379> zcount myzset 1 4
(integer) 4
127.0.0.1:6379> zcount myzset (1 (4
(integer) 2
1.4 ZRANGE
返回指定区间内的元素,元素按升序,带上withscores可以把分数也返回
ZRANGE key start stop [WITHSCORES]
- 时间复杂度:O(log(N)+M)
- 返回值:区间内的元素列表。
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
127.0.0.1:6379> zrange myzset 1 4
1) "two"
2) "three"
3) "four"
1.5 ZREVRANGE
返回指定区间内的元素,元素按照降序,带上withscores可以把分数也返回
ZREVRANGE key start stop [WITHSCORES]
- 时间复杂度:O(log(N)+M)
- 返回值:区间内的元素列表。
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
127.0.0.1:6379> zrevrange myzset 1 4
1) "three"
2) "two"
3) "one"
1.6 ZRANGEBYSCORE
返回分数在min和max之间的元素,默认情况下min和max都包含,可以通过( 排除
ZRANGEBYSCORE key min max [WITHSCORES]
- 时间复杂度:O(log(N)+M)
- 返回值:区间内的元素列表。
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
127.0.0.1:6379> zrangebyscore myzset 1 4
1) "one"
2) "two"
3) "three"
4) "four"
127.0.0.1:6379> zrangebyscore myzset (1 (4
1) "two"
2) "three"
1.7 ZPOPMAX
删除并返回分数最高的count个元素
ZPOPMAX key [count]
- 时间复杂度:O(log(N) * M)
- 返回值:分数和元素列表。
127.0.0.1:6379> zpopmax myzset
1) "four"
2) "4"
127.0.0.1:6379> zpopmax myzset 3
1) "three"
2) "3"
3) "two"
4) "2"
5) "one"
6) "1"
1.8 ZPOPMIN
删除并返回分数最低的count个元素
ZPOPMIN key [count]
- 时间复杂度:O(log(N) * M)
- 返回值:分数和元素列表。
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
127.0.0.1:6379> zpopmin myzset
1) "one"
2) "1"
127.0.0.1:6379> zpopmin myzset 3
1) "two"
2) "2"
3) "three"
4) "3"
5) "four"
6) "4"
1.9 BZPOPMIN
zpopmin的阻塞版本
BZPOPMIN key [key ...] timeout
- 时间复杂度:O(log(N))
- 返回值:元素列表。
1.10 ZRANK
按照升序返回指定元素的排名
ZRANK key member
- 时间复杂度:O(log(N))
- 返回值:排名。
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
127.0.0.1:6379> zrank myzset two
(integer) 1
127.0.0.1:6379> zrank myzset one
(integer) 0
127.0.0.1:6379> zrange myzset 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
1.11 ZREVRANK
按降序返回指定元素的排名
ZREVRANK key member
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
127.0.0.1:6379> zrange myzset 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
127.0.0.1:6379> zrevrank myzset one
(integer) 3
127.0.0.1:6379> zrevrank myzset four
(integer) 0
1.11 ZSCORE
返回指定元素的分数
ZSCORE key member
- 时间复杂度:O(1)
- 返回值:分数。
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three 4 four
(integer) 4
127.0.0.1:6379> zscore myzset one
"1"
1.12 ZREM
删除指定的元素
ZREM key member [member ...]
- 时间复杂度:O(M*log(N))
- 返回值:本次操作删除的元素个数。
127.0.0.1:6379> zrange myzset 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
127.0.0.1:6379> zrem myzset one two
(integer) 2
127.0.0.1:6379> zrange myzset 0 -1
1) "three"
2) "four"
1.13 ZREMRANGEBYRANK
按照排序,升序删除指定范围内的元素,左闭右闭
ZREMRANGEBYRANK key start stop
- 时间复杂度:O(log(N)+M)
- 返回值:本次操作删除的元素个数。
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "four"
8) "4"
127.0.0.1:6379> zremrangebyrank myzset 1 2
(integer) 2
127.0.0.1:6379> zrange myzset 0 -1
1) "one"
2) "four"
1.14 ZREMRANGEBYSCORE
按照分数删除指定区间内的元素,左闭右闭
ZREMRANGEBYSCORE key min max
- 时间复杂度:O(log(N)+M)
- 返回值:本次操作删除的元素个数。
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "four"
8) "4"
127.0.0.1:6379> zremrangebyscore myzset 1 2
(integer) 2
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "three"
2) "3"
3) "four"
4) "4"
1.15 ZINCRBY
为指定元素的关联分数添加指定的分数值
ZINCRBY key increment member
- 时间复杂度:O(log(N))
- 返回值:增加后元素的分数。
127.0.0.1:6379> zscore myzset four
"4"
127.0.0.1:6379> zincrby myzset 10 four
"14"
127.0.0.1:6379> zscore myzset four
"14"
127.0.0.1:6379> zincrby myzset -10 four
"4"
127.0.0.1:6379> zscore myzset four
"4"
2. 集合间操作
2.1 ZINTERSTORE
求出给定有序集合的交集并保存到目标集合中,在合并中元素按照约定好的权重计算后相加写入目标有序集合中
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight[weight ...]] [AGGREGATE <SUM | MIN | MAX>]
- 时间复杂度:O(N*K)+O(M*log(M)) N 是输⼊的有序集合中, 最⼩的有序集合的元素个数; K 是输⼊了⼏个有序集合; M 是最终结果的有序集合的元素个数.
- 返回值:⽬标集合中的元素个数
127.0.0.1:6379> zadd zset1 1 one 2 two
(integer) 2
127.0.0.1:6379> zadd zset2 1 one 2 two
(integer) 2
127.0.0.1:6379> zinterstore myzset 2 zset1 zset2 weights 2 3
(integer) 2
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "one"
2) "5"
3) "two"
4) "10"
2.2 ZUNIONSTORE
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight[weight ...]] [AGGREGATE <SUM | MIN | MAX>]
- 时间复杂度:O(N)+O(M*log(M)) N 是输⼊的有序集合总的元素个数; M 是最终结果的有序集合的元素个数.
- 返回值:⽬标集合中的元素个数
redis> ZADD zset1 1 "one"
(integer) 1
redis> ZADD zset1 2 "two"
(integer) 1
redis> ZADD zset2 1 "one"
(integer) 1
redis> ZADD zset2 2 "two"
(integer) 1
redis> ZADD zset2 3 "three"
(integer) 1
redis> ZUNIONSTORE out 2 zset1 zset2 WEIGHTS 2 3
(integer) 3
redis> ZRANGE out 0 -1 WITHSCORES
1) "one"
2) "5"
3) "three"
4) "9"
5) "two"
6) "10"
3. 内部编码
有序集合类型的内部编码有两种:
- ziplist(压缩列表):当有序集合的元素个数⼩于 zset-max-ziplist-entries 配置(默认 128 个),同时每个元素的值都⼩于 zset-max-ziplist-value 配置(默认 64 字节)时,Redis 会⽤ ziplist 来作为有序集合的内部实现,ziplist 可以有效减少内存的使⽤。
- skiplist(跳表):当 ziplist 条件不满⾜时,有序集合会使⽤ skiplist 作为内部实现,因为此时 ziplist 的操作效率会下降。
当元素个数较少且每个元素大小较小时,内部编码为ziplist:
127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3
(integer) 3
127.0.0.1:6379> object encoding zsetkey
"ziplist"
当元素个数超过128个时,内部编码为skiplist:
127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3 ... 省略 ... 82 e129
(integer) 129
127.0.0.1:6379> object encoding zsetkey
"skiplist"
当某个元素大于64字节时,内部编码为skiplist:
127.0.0.1:6379> zadd zsetkey 50 "one string bigger than 64 bytes ... 省略 ..."
(integer) 1
127.0.0.1:6379> object encoding zsetkey
"skiplist"
五、总结
以上四个加上String类型就是Redis中最常用的五种数据类型,这五种数据类型已经能囊括大部分的使用场景,在有些特殊场景我们或许还是需要借助另外五个数据类型,那五种数据类型也不是很难,用到的时候再自己查文档学习即可
感谢各位大佬观看,创作不易,还望各位大佬点赞支持!!!