Redis中有常见数据类型

Redis的数据类型

string数据类型

string是redis最基本的类型,而且string类型是二进制安全的。意思是redis的string可以包含任何 数据,比如jpg图片或者序列化的对象

String类型是最基本的数据类型,一个redis中字符串value最多可以是512M

redis底层提供了三种不同的数据结构实现字符串对象,根据不同的数据自动选择合适的数据结 构。这里的字符串对象并不是指的纯粹的字符串,数字也是可以的

当保存的数据中包含字符时,String类型就会用简单动态字符串SDS结构体来保存

  •  redis中的String并不是以\0结束,而是根据len来决定文件是否结束。其主要目的是为了存储 非String的数据,例如图片,影像等二进制数据
  • 由于String结构体中存储了长度,所以在获得长度的时间复杂度为O(1)
  • String在扩容的时候,如果数据的长度小于10MB则,每次扩容为之前以后数据的2倍。如果超 过10MB则每次只增加1MB的长度 

主要应用场景:

  • 1、存储数据。如常见存储 K-V 字符串、JSON字符串。
  • 2、程序计数 INCR 命令递 增或递增一个数。
  • 3、分布式锁,使用 SET key value NX ,NX 不存在才写入。
  • 4、单点登录。可作 为存储共享会话实现单点登录。 

Hash数据类型

hash类型实际上是以key为标识存储key-value对。redis hash是一个string类型的field和value的映射 表,添加,删除操作都是平均O(1),hash特别适合用于存储对象 

有压缩链表ziplist和字典结构hashtable两种底层实现 

  • hashtable采用链地址法解决hash冲突问题
  • 当hash对象可以同时满足以下两个条件时,哈希对象使用ziplist编码,超过限制则使用 hashtable结构存储数据 

                哈希对象保存的所有键值对的键和值的字符串长度都小于64字节

                哈希对象保存的键值对数量小于512个 

ziplist编码的哈希对象使用压缩列表作为底层实现, 每当有新的键值对要加入到哈希对象时,会先 将保存了键的压缩列表节点推入到压缩列表表尾, 然后再将保存了值的压缩列表节点推入到压缩 列表表尾。

因此保存了同一键值对的两个节点总是紧挨在一起, 保存键的节点在前, 保存值的节点在后;先 添加到哈希对象中的键值对会被放在压缩列表的表头方向,而后来添加到哈希对象中的键值对会被 放在压缩列表的表尾方向

压缩列表并不是对数据利用某种算法进行压缩,而是将数据按照一定规则编码在一块连续的 内存区域,目的是节省内存

优点: 内存地址连续,省去了每个元素的头尾节点指针占用的内存

缺点: 对于删除和插入操作比较可能会触发连锁更新反应,比如在list中间插入删除一个元素 时,在插入或删除位置后面的元素可能都需要发生相应的移位操作。 

hashtable 编码的哈希对象使用字典作为底层实现, 哈希对象中的每个键值对都使用一个字典键 值对来保存:

  • 字典的每个键都是一个字符串对象, 对象中保存了键值对的键
  • 字典的每个值都是一个字符串对象, 对象中保存了键值对的值 

Hash类型两种编码方式,ziplist 与 hashtable。

  • hashtable 编码的哈希对象使用字典作为底层实现

ziplist 与 hashtable 编码方式之间存在单向转换

  • 既想节省Redis内存空间,又想存储对象数据,又想访问速度快,hash似乎是不二的选择 

List数据类型 

list是redis的一种基础数据结构,内部使用双向链表quicklist实现,所以向列表两端添加元素的时间复杂 度为O(1), 获取越接近两端的元素速度就越快 

redis中的列表对象经常被用作消息队列使用,底层有双向链表linkedList、支持双向遍历的压缩列表 zipList和quickList三种存储方式 

  • 在Redis3.2版本后,引入的qucikList是zipList和双向链表linkedList组成的混合体 

可以作链表使用 

双向链表linkedList链表是双端结构,listNode结构体中带有prev和next指针,因此获取某个节点 的前置节点和后继节点的时间复杂度都是O(1) 

  • 这个链表无环:表头节点的prev和表尾节点的next指针都指向了NULL,对链表的访问以 NULL为终点
  • 带表头指针和表尾指针:通过list结构的head指针和tail指针,程序获取链接的表头节点和表 尾节点的时间复杂度为O(1)
  • 带有链表长度计数器:程序使用list结构体的len属性来对list持有的链表节点进行计数,程序 获取链表中节点数量的复杂度为O(1)
  • 多态:链表节点使用void*指针来保存节点值,可以用于保存不同类型的值 

ziplist和linkedlist 

因为双向链表占用的内存比压缩列表要多, 所以当创建新的列表键时, 列表会优先考虑使用压缩 列表, 并且在有需要的时候, 才从压缩列表实现转换到双向链表实现

试图往列表新添加一个字符串值,且这个字符串的长度超过默认值64或者ziplist 包含的节点超过 默认值为 512 

因为双向链表占用的内存比压缩列表要多, 所以当创建新的列表键时, 列表会优先考虑使用压缩 列表, 并且在有需要的时候, 才从压缩列表实现转换到双向链表实现 试图往列表新添加一个字符串值,且这个字符串的长度超过默认值64或者ziplist 包含的节点超过 默认值为 512 

Redis中的列表list,在版本3.2之前,列表底层的编码是ziplist和linkedlist实现的,但是在版本3.2之后, 重新引入 quicklist,列表的底层都由quicklist实现。 

双向链表linkedlist便于在表的两端进行push和pop操作,在插入节点上复杂度很低,但是它的内 存开销比较大。首先,它在每个节点上除了要保存数据之外,还要额外保存两个指针;其次,双向 链表的各个节点是单独的内存块,地址不连续,节点多了容易产生内存碎片。

quickList是ziplist和linkedlist二者的结合,是一个ziplist组成的双向链表。每个节点使用ziplist来 保存数据。本质上来说,quicklist里面保存着一个一个小的ziplist

quickList就是一个标准的双向链表的配置,有head有tail;每个节点是一个quicklistNode,包含 prev和next指针。每一个quicklistNode包含一个ziplist,压缩链表里存储键值。所以quicklist是对 ziplist进行一次封装,使用小块的ziplist来既保证了少使用内存,也保证了性能。 

应用场景: 

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

Zset有序集合 

有序集合对象zset和集合对象set没有很大区别,仅仅是多了一个分数score用来排序 

  • redis中的有序集合底层采用ziplist和skiplist跳表实现,当所有字符串长度都小于设定值值64字 节,并且所存元素数量小于设定值512个使用ziplist实现,其他情况均使用skiplist实现
  • 当ziplist作为zset的底层存储结构时候,每个集合元素使用两个紧挨在一起的压缩列表节点来保 存,第一个节点保存元素的成员,第二个元素保存元素的分值
  • 有序集合的底层实现之一是跳表, 除此之外跳表它在 Redis 中没有其他应用 
  • 整数集合intset是集合键的底层实现之一: 当一个集合只包含整数值元素, 并且这个集合的元素数 量不多时, Redis 就会使用整数集合作为集合键的底层实现
  • 数据少时使用ziplist压缩列表,占用连续内存,每项元素都是(数据+score)的方式连续存储,按照 score从小到大排序。ziplist为了节省内存,每个元素占用的空间可以不同,对于大数据(long long),就多用一些字节存储,而对于小的数据(short),就少用一些字节来存储。因此查找的时候需 要按顺序遍历。ziplist省内存但是查找效率低
  • 跳跃表是一种有序数据结构,它通过在每个节点中维持多个指向其它节点的指针,从而达到快速访 问节点的目的,具有以下性质:

有很多层结构组成

每一层都是一个有序的链表,排列顺序为由高到低,都至少包含两个链表节点,分别是前面的 head节点和后面的nil节点

最底层的链表包含了所有的元素

如果一个元素出现在某一层的链表中,那么在该层之下的链表也全部都会出现

链表中的每个节点都包含两个指针,一个指向同一层的下一个链表节点,另一个指向下一层的 同一个链表节点 

  •  搜索,从最高层的链表节点开始,如果比当前节点要大和比当前层的下一个节点要小,那么则往下 找,也及时和当前层的下一层的节点下一个节点
  • 插入,首先确定插入的层数,有一种方法是抛一个硬币,如果是正面就累加,直到遇到反面为止, 最后记录正面的次数作为插入的层数,当确定插入的层数K后,则需要将新元素插入从底层到K层
  • 删除,在各个层中找到包含指定值得节点,然后将节点从链表中删除即可,如果删除以后只剩下头 尾两个节点,则删除这一层

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值