Redis数据结构和内部编码

一、Redis五种外部数据结构

redis的数据结构分别是:

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

每一种数据结构都对应着多个的内部编码,redis根据实际情况选择合适的内部编码。可以通过object encoding命令查询内部编码

1
2
3
4
5
127.0.0.1:6379> rpush test a b c d e f  #创建一个list
(integer) 6

127.0.0.1:6379> object encoding test #查看内部编码
"quicklist"

redis数据结构和内部编码对应如下图

image_1

这样设计的好处:

  • 一、可以改进内部编码。如list内部编码中quicklist为后来新增,用户可以无感知的使用到新的内部编码特性。
  • 二、多种内部编码可以在多种不同场景下发挥自己的优势。

二、字符串

字符串是redis的基础类型,其他的数据结构都是构建在字符串基础之上,字符串类型的值可以是字符串、JSON、XML、数字(整数、浮点数)、二进制(视频、音频的二进制)。

注意:字符串值最大不能超过512M。

1、字符串的相关命令

(1)设置值的命令

1
2
3
4
5
set key value [ex seconds] [px millisecond] nx|xx

#例子
127.0.0.1:6379> set hello world
OK

set 命令选项

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

2、字符串内部编码

字符串类型有3种内部编码:

  • int:8个字节的长整型
  • embstr:小于等于39个字节的字符串
  • raw:大于39个字节的字符串

redis根据当前值的类型和长度选择使用哪种内部编码。

三、哈希

哈希是指redis键值对中的值又是一个键值对,如下图:

image_2

1、哈希相关命令

(1)设置值的命令

1
2
3
4
5
6
#设置值
hset key field value

#例子
127.0.0.1:6379> hset test_1 world helloworld
(integer) 1

(2)获取值的命令

1
2
3
4
5
6
#获取值
hget key field

#例子
127.0.0.1:6379> hget test_1 world
"helloworld"

2、哈希内部编码

哈希类型的内部编码有两种:

  • ziplist:当哈希类型的元素个数小于hash-max-ziplist-entries配置(默认512个),且所有值都小于hash-max-ziplist-value的配置(默认64字节)时,Redis会使用ziplist作为哈希类型内部编码,相比hashtable更加节省空间。
  • hashtable:当哈希类型无法满足ziplist的条件时,Redis会使用hashtable作为哈希内部编码,hashtable的读写时间负责度为O(1)。

四、列表

列表(list)是用来存储多个有序的字符串,列表中每个字符串称为元素,一个列表最多存储2^32 - 1个元素,在Redis中可以对列表两端插入(push)和弹出(pop),还可以获取指定范围的列表元素,获取指定下标的元素,通常用作栈或队列。

image_3

列表特点:

  • 元素是有序的:可以通过索引获取某个或者某个范围的元素
  • 元素可以重复:同Java List

1、列表相关命令

(1)从右边插入元素

1
2
3
4
rpush key value [value ...]

127.0.0.1:6379> rpush test_2 a b c d e f
(integer) 6

从左边插入元素为lpush key value [value …]

(2)查找指定范围元素

1
2
3
4
5
lrange key start end

127.0.0.1:6379> lrange test_3 0 1
1) "a"
2) "b"

lrange命令的下标从左到右分别为0到N-1,从右到左分别是-1到-N,另外,lrange获取的元素范围时包含start和end下标元素,即左右都是闭区间。

(3)从列表左侧弹出元素

1
2
3
4
lpop key

127.0.0.1:6379> lpop test_3 #最左侧a会被弹出
"a"

从右侧弹出为rpop key

(4)删除指定元素

1
2
3
4
lrem key count value

127.0.0.1:6379> lrem test_3 1 b #最左侧b会被删除
(integer) 1

lrem命令会从列表中查找等于value的元素,根据count不同进行删除

  • count > 0,从左到右删除最多count个元素
  • count < 0,从右到左删除最多|count|个元素
  • count = 0,删除所有

2、列表内部编码

列表类型的内部编码有三种:

  • ziplist:当列表中元素个数小于list-max-ziplist-entries配置(默认512个),且列表中每个元素值都小于list-max-ziplist-value配置(默认64字节)时,Redis会使用ziplist作为列表内部编码。
  • linkedlist:当列表无法满足ziplist条件时,Redis使用linkedlist作为列表内部编码。
  • quicklist:是一个用ziplist作为节点的linkedlist,它结合了ziplist和linkedlist的优势。

3、使用场景

(1)消息队列,(2)文章列表

五、集合

集合也是用来保存多个字符串元素,但是集合是无序的、不可重复的,不可以通过下标查找元素,一个集合最多可以存储2^32 - 1个元素,Redis除了支持集合的增删改查,还支持多个集合的交集、并集、差集操作。

1、集合相关命令

(1)添加元素

1
2
3
4
sadd key element [element ...]

127.0.0.1:6379> sadd test_4 a b a
(integer) 2

(2)删除元素

1
2
3
4
srem key element [element ...]

127.0.0.1:6379> srem test_4 a
(integer) 1

(3)交集

1
2
3
4
sinter key [key ...]

127.0.0.1:6379> sinter test_4 test_5
1) "a"

2、集合内部编码

集合内部编码有两种

  • intset整数集合:当集合中元素都是整数且元素个数小于set-max-intset-entries配置(默认512个),Redis会使用intset作为集合的内部编码
  • hashtable哈希表:当集合类型无法满足intset条件时,Redis会使用hashtable作为内部编码

六、有序集合

有序集合和集合类似,存储多个字符串元素,集合中元素不能重复,但是有序集合可以排序,但是这个排序和列表不同,有序集合是给每一个元素设置一个分数(score),有序集合根据元素的score进行排序。

image_4

1、有序集合相关命令

(1)添加成员

1
2
3
4
zadd key score member [score member ...]

127.0.0.1:6379> zadd test_6 1 a 2 b 3 c 4 d
(integer) 4

zadd命令还有几个选项

  • nx:member必须不存在,才可以设置成功,用于添加
  • xx:member必须存在,才可以设置成功,用于更新
  • ch:返回操作后有序集合和分数变化的个数
  • incr:对score做增加

有序集合添加元素的时间复杂度为O(log(n)),集合添加元素的时间复杂度为O(1)。

2、有序集合内部编码

有序集合有两种内部编码

  • ziplist压缩列表:当列表中元素个数小于zset-max-ziplist-entries配置(默认512个),且列表中每个元素值都小于zset-max-ziplist-value配置(默认64字节)时,Redis会使用ziplist作为列表内部编码。
  • skiplist跳跃表:当ziplist条件不满足时,有序集合会使用skiplist作为内部编码,但读写效率会下降。

3、使用场景

(1)用户点赞功能

坚持原创技术分享,您的支持将鼓励我继续创作!