Redis 数据类型

数据类型

基础数据类型

String

字符串类型(SDS)即简单动态字符串,它是以键值对key-value的形式进行存储的,根据 key 来存储和获取value值

依据不同情况,字符串在底层会使用 int 、 raw 或者 embstr 三种不同的编码格式

  • 如果数据为可以使用long类型来保存的整数,则使用int
  • 如果数据为可以使用long double类型来保存的浮点数,则使用embstr或者raw
  • 如果数据为字符串,或者长度过大没办法用long来表示的整数,以及长度过大无法用long double表示的浮点数,则使用embstr或者raw。当数据小于39字节时,使用embstr,当大于39字节时使用raw

在这里插入图片描述 在这里插入图片描述

基本用法

1
2
3
4
5
6
127.0.0.1:6379> set hello world	//设置key-value
OK
127.0.0.1:6379> get hello	//根据key获取value
"world"
127.0.0.1:6379> strlen hello	//计算value长度
(integer) 5

在这里插入图片描述

使用场景

  • 存放用户(登录)信息;
  • 存放文章详情和列表信息;
  • 存放和累计网页的统计信息。

Hash

字典类型 (Hash) 又被成为散列类型或者是哈希表类型,它是将⼀个键值 (key) 和⼀个特殊的“哈希表”关联起来。 在这里插入图片描述

哈希类型的底层数据结构可以是压缩列表(ZipList)或者字典(Dict)

  • 当哈希对象的所有键值对的键和值的字符串长度都小于64字节,并且保存的键值对数量小于512个时,使用压缩列表
  • 如果不满足上述条件中的任意一个,都会使用字典 在这里插入图片描述 在这里插入图片描述

在这里插入图片描述

基本用法

1
2
3
4
5
6
127.0.0.1:6379> hset hash1 name lee age 20	//设置key-value的映射
(integer) 2
127.0.0.1:6379> hget hash1 name	//获取key为name的value
"lee"
127.0.0.1:6379> hget hash1 age	//获取key为age的value
"20"

在这里插入图片描述

使用场景

  • 存储用户信息或者某个物品的信息,无需序列化,直接建立映射

List

列表类型 (List) 是⼀个使用线性结构存储的结构,它的元素插入会按照先后顺序存储到链表结构中。 列表类型的底层数据结构可以是压缩列表(ZipList)或者链表(LinkedList)

  • 当列表对象的所有字符串元素长度都小于64字节,并且保存的元素数量小于512个时,使用压缩列表
  • 如果不满足上述条件中的任意一个,都会使用链表 在这里插入图片描述 在这里插入图片描述

基本用法

1
2
3
4
5
6
127.0.0.1:6379> lpush list1 1 2 3 4 5	//依次头插1 2 3 4 5,此时数据为5 4 3 2 1
(integer) 5
127.0.0.1:6379> rpop list1	//尾删
"1"
127.0.0.1:6379> lpop list1	//头删
"5"

在这里插入图片描述

使用场景

  • 消息队列:列表类型可以使用 rpush 实现先进先出的功能,同时又可以使用 lpop 轻松的弹出(查询并删除)第⼀个元素,所以列表类型可以用来实现消息队列;
  • 文章列表:对于博客站点来说,当用户和文章都越来越多时,为了加快程序的响应速度,我们可以把用户自己的文章存入到 List 中,因为 List 是有序的结构,所以这样不仅可以完美的实现分页功能,而且加速了程序的响应速度。

Set

集合类型 (Set) 是⼀个无序并唯⼀的键值集合。

集合类型的底层数据结构可以是整数集合(IntSet)或者字典(Dict)

  • 当集合对象的所有元素都是整数值,并且保存的元素数量小于512个时,使用整数集合
  • 如果不满足上述条件中的任意一个,都会使用字典 在这里插入图片描述 在这里插入图片描述

基本用法

1
2
3
4
5
6
7
127.0.0.1:6379> sadd testSet v1 v2 v3 v4 v2 v4 v1
(integer) 4
127.0.0.1:6379> smembers testSet	//去重且无序
1) "v2"
2) "v1"
3) "v4"
4) "v3"

在这里插入图片描述

使用场景

  • 微博关注我的人和我关注的人都适合用集合存储,可以保证人员不会重复;
  • 中奖人信息也适合用集合类型存储,这样可以保证⼀个人不会重复中奖。

Zset

有序集合类型 (SortedSet) 相比于集合类型多了⼀个排序属性 score(分值),所以对于有序集合ZSet 来说,每个存储元素相当于有两个值组成的,⼀个是有序结合的元素值,⼀个是分值。有序集合的存储元素值也是不能重复的,但分值是可以重复的。

有序集合类型的底层数据结构可以是压缩列表(ZipList)或者跳表(SkipList )

  • 当有序集合对象的所有元素成员的长度都小于64字节,并且保存的元素数量小于128个时,使用压缩列表
  • 如果不满足上述条件中的任意一个,都会使用跳表(这里的跳表是结合字典的) 在这里插入图片描述 在这里插入图片描述 这里不是直接使用跳表,而是搭配字典一起使用 之所以这样设置是因为考虑到如果直接使用跳跃表,如果需要查找成员的分值时只能通过遍历来进行查找,而这样的效率是O(logN) 而字典虽然建立映射后可以O(1)的查找到分值,但是哈希只能通过key值进行查找,并不支持范围查询。 所以将两者进行结合,使用字典建立起元素与分值的映射,使用字典来进行成员分数的查找,而使用跳跃表来进行范围型操作,这样就很好的解决了这个问题。
1
2
3
4
5
typedef struct zset {
    zskiplist *zsl;

    dict *dict;
} zset;

在这里插入图片描述

在这里插入图片描述

基本用法

1
2
3
4
5
6
7
127.0.0.1:6379> zadd zset1 3 v1 8 v2 2 v3 6 v4	#插入时以分值-值的形式插入
(integer) 4
127.0.0.1:6379> zrange zset1 0 -1	#查找结果按照升序排序
1) "v3"
2) "v1"
3) "v4"
4) "v2"

在这里插入图片描述

使用场景

  • 学生成绩排名;
  • 粉丝列表,根据关注的先后时间排序。

特殊数据类型

Geospatial(地理空间)

在使用一些小程序的时候,里面通常都会通过定位使用者的位置,来显示附近的人、外卖距离、剩余路径等功能,在Redis3.2中也引入了推算地理信息的数据结构,即Geospatial

介绍

把某个具体的位置信息(经度,纬度,名称)添加到指定的key中,数据将会用一个sorted set存储,以便稍后能使用 GEORADIUS和 GEORADIUSBYMEMBER命令来根据半径来查询位置信息。

这个命令(指GEOADD)的参数使用标准的x,y形式,所以经度(longitude)必须放在纬度(latitude)之前,对于可被索引的坐标位置是有一定限制条件的:非常靠近极点的位置是不能被索引的, 在EPSG:900913 / EPSG:3785 / OSGEO:41001指定如下:

  • 有效的经度是-180度到180度
  • 有效的纬度是-85.05112878度到85.05112878度

上面是官方文档的描述,其实Geo并没有我们想象中的复杂,它的本质就是一个Zset,通过将坐标以Geohash的方式进行处理,将经度纬度错位后形成一个52位整数,所以我们同样能够使用Zset提供的接口来操作Geo

用法

命令 作用
GEOADD key 经度 纬度 地点名称 将指定的地理空间位置(经度、纬度、名称)添加到指定的key中
GEODIST key 地点1 地点2 返回两个给定位置之间的距离
GEOPOS key 地点 从key里返回所有给定位置元素的位置(经度和纬度)
GEOHASH key 地点 返回一个或多个位置元素的 Geohash 表示
GEORADIUS key 经度 纬度 半径 以给定的经纬度为中心, 找出某一半径内的元素
GEORADIUSBYMEMBER key 地点 半径 找出位于指定范围内的元素,中心点是由给定的位置元素决定
Zset的接口同样适用于Geo,因此需要删除、查询全部时就可以使用Zset的接口。

下面示范一下这些命令的使用方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 为了方便示范,下面加入一些城市的地理信息——GEOADD 
127.0.0.1:6379> GEOADD CHINA 108.94683  34.29296  "xian"
(integer) 1
127.0.0.1:6379> GEOADD CHINA 116.405285 39.904989 "beijing"
(integer) 1
127.0.0.1:6379> GEOADD CHINA 121.472644 31.231706 "shanghai"
(integer) 1
127.0.0.1:6379> GEOADD CHINA 113.280637 23.125178 "guangzhou"
(integer) 1
127.0.0.1:6379> GEOADD CHINA 114.085947 22.547    "shenzhen"
(integer) 1
127.0.0.1:6379> GEOADD CHINA 110.33119  20.031971 "hainan"
(integer) 1

# 获取北京和上海的距离——GEODIST 
127.0.0.1:6379> GEODIST CHINA beijing shanghai km
"1067.5980"

# 获取西安的坐标——GEOPOS 
127.0.0.1:6379> GEOPOS CHINA xian
1) 1) "108.94683212041854858"
   2) "34.29296115814533863"

# 以经度120 纬度35位置为中心,获取半径1000千米内的城市——GEORADIUS 
127.0.0.1:6379> GEORADIUS CHINA 120 35 1000 km
1) "beijing"
2) "shanghai"

# 获取在广州半径500千米内的城市——GEORADIUSBYMEMBER  
127.0.0.1:6379> GEORADIUSBYMEMBER CHINA guangzhou 500 km
1) "shenzhen"
2) "guangzhou"
3) "hainan"

# 将广州和深圳的坐标转换为11为的GEO哈希值——GEOHASH
127.0.0.1:6379> GEOHASH CHINA guangzhou shenzhen
1) "ws0e9cb3yj0"
2) "ws10k0dcg10"

Hyperloglog(基数统计)

在我们为网站统计访问量、日活量时,由于我们统计的是用户数量而非访问次数,因此即使一个用户多次访问也只会统计一次,这种不重复的数据通常被称为基数

在传统的做法中,我们通常会采用set来保存用户的ID来进行计数,因为其本身存在着去重的功能,但是由于我们所需要的是对用户进行计数,如果通过将所有用户的ID保存的方法来完成,当用户量大的时候就会对内存产生巨大的压力,并且效率也大大降低。

为了解决这个问题,Redis在2.8.9版本添加了HyperLogLog结构。

介绍

Redis HyperLogLog是用来做基数统计的算法,HyperLogLog的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的

在Redis 里面,每个HyperLogLog键只需要花费12KB内存,就可以计算接近2^64个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,由于HyperLogLog使用的是概率算法,通过存储元素的hash值的第一个1的位置,来计算元素数量,所以HyperLogLog 不会存储元素本身,在数据量大的时候也可能会存在一定的误差。但是在基数统计这一方面,它的效果是其他结构无法比拟的。

用法

命令 作用
PFADD key value 添加指定的值到Hyperloglog中
PFCONUT key 返回给定Hyperloglog的基数估算值
PFMERGE destkey sourcekey 将目标Hyperloglog合并到源Hyperloglog中

使用示范

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
127.0.0.1:6379> PFADD NUMS1 1 2	3 4	#向NUMS1插入1-4
(integer) 1
127.0.0.1:6379> PFADD NUMS1 1		#数据已存在,不再插入
(integer) 0
127.0.0.1:6379> PFCOUNT NUMS1		#查看当前基数数量
(integer) 4

127.0.0.1:6379> PFADD NUMS2 3 4 5 6	#向NUMS2插入3-6
(integer) 1
127.0.0.1:6379> PFMERGE NUMS1 NUMS2	#将NUMS2合并到NUMS1中
OK
127.0.0.1:6379> PFCOUNT NUMS1		#此时NUMS1中记录了1-6,六个元素
(integer) 6									

Bitmap(位图)

介绍

位图其实就是哈希的变形,他通过哈希映射来处理数据,位图本身并不存储数据,而是存储标记。通过一个比特位,即0/1来标记一个数据的两种状态

位图通常情况下用在数据量庞大,且数据不重复的情景下标记某个数据的两种状态。 我们可以使用位图来记录当前用户的登陆情况、或者实现打卡、签到等功能。

用法

命令 作用
GETBIT key offset value(0/1) 设置Bitmap中偏移量为offset的位置的值
SETBIT key offset value 返回Bitmap中偏移量为offset的位置的值
BITCOUNT key 计算位图中有多少个1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
127.0.0.1:6379> SETBIT TEST 1 1	#将位图中第1,3,5位设置为1
(integer) 0
127.0.0.1:6379> SETBIT TEST 3 1
(integer) 0
127.0.0.1:6379> SETBIT TEST 5 1
(integer) 0

127.0.0.1:6379> GETBIT TEST 1 	#查看位图中1,2,3位的值
(integer) 1
127.0.0.1:6379> GETBIT TEST 2
(integer) 0
127.0.0.1:6379> GETBIT TEST 3
(integer) 1

127.0.0.1:6379> BITCOUNT TET	#统计位图中1的数量,由于我们只设置了1,3,5位,因此为3
(integer) 3
Built with Hugo
主题 StackJimmy 设计