整数集合

Redis 中当一个集合(set)中只包含整数,并且元素不多时,底层使用整数集合实现,否则使用字典实现。

那么:

  • 为什么会出现整数集合呢?都使用字典存储不行吗?
  • 整数集合在 Redis 中的结构是怎样的呢?
  • 引入整数集合之后,会不会出现什么弊端?Redis 又是如何去解决的呢?

为什么会出现整数集合呢?都使用字典存储不行吗?

说起无序集合(set),很自然的就想起哈希表,而哈希表表现也很好,提供了查询为 O(1) 的时间复杂度。但任何事物有优点,就必然会伴随着一些缺点,哈希表的缺点就是使用的储存空间大,其实哈希表本身就是空间换取时间的一种方式。

Redis 作为一个缓存,考虑到内存的使用,所以出现了整数集合这一数据结构。然而整数集合虽然相比哈希表很节约内存,但它也是牺牲了速度作为代价的。所以 Redis 中也只是在数据量少的条件下才会去使用整数集合代替哈希表。

整数集合在 Redis 中的结构是怎样的呢?

Redis 中的整数集合由 intset.h/intset 表示,具体结构如下:

typedef struct intset {

    // 编码方式
uint32_t encoding; // 集合包含的元素数量
uint32_t length; // 保存元素的数组
int8_t contents[]; } intset;

length属性表示整数集合包含的元素数量,即是contents数组的长度。

contents 数组是整个整数集合最核心的部分,元素就存储在这个数组中,各个元素从小到大有序排列,并且没有重复元素。虽然 contents 数组是声明成int8_t的类型,但是存储元素的真正类型并不是 int8_t 而是由 encoding 属性来表示 contents 数组真正的类型。比如:

  • 如果 encoding 属性的值为 INTSET_ENC_NT16,那么 contents 就是一个 int16_t 类型的数组,数组里的每个项都是一个 int16_t 类型的整数值(最小值为 -32768,最大值为 32767)。
  • 如果 encoding 属性的值为 INTSET_ENC_NT32,那么 contents 就是一个 int32_t 类型的数组,数组里的每个项都是一个 int32_t 类型的整数值(最小值为 -2^31,最大值为 2^31-1)。

引入整数集合之后,会不会出现什么弊端?

当我们向集合中插入元素时,Redis 并没有让我们指定插入的数值是几个字节的,那么如果我们先插入了 int16_t 的元素,然后插入了一个 int32_t 的元素,那么这时候原来的 contents 存不了新插入的值,这个时候该怎么做呢? 这也就是 Redis 引入整数集合之后所要解决的问题。

Redis 为了解决这个问题,于是引入了升级。

升级

每当我们要将一个新元素添加到整数集合里面,并且新元素的类型比整数集合现有所有元素的类型都要长时,整数集合需要先进行升级,然后才能将新元素添加到整数集合里面。具体步骤如下:

  1. 根据新元素的类型,扩展整数集合底层数组的空间大小,并为新元素分配空间。
  2. 将底层数组现有的所有元素都转换成与新元素相同的类型,并将类型转换后的元素
  3. 将新元素添加到底层数组(contents)里面。

升级的时间复杂度是 O(n),又每次向整数集合添加新元素都可能引发升级,所以整数集合添加新元素的时间复杂度是 O(n)。

而为整数集合引入升级之后,主要带来了两点好处:

第一:提升了程序的灵活性。

第二:节约内存。

看到这里,可能有的人会想,有了升级,那么有没有降级呢?很遗憾,Redis 中的整数集合没有降级,也就是说只能扩容,不能缩容。

压缩列表

本篇只是简单介绍一下压缩列表,所以暂不深入讲解,感兴趣的可以自行查阅其他资料。

Redis 在什么情况下会使用压缩列表作为底层实现呢?

  1. 列表只包含少量元素,并且每个列表项要么是小整数值,要么是长度较短的字符串。
  2. 哈希键中只包含少量键值对,并且每个键值对的键和值要么是小整数值,要么是长度较短的字符串。

其实看到压缩二字,就能联想到节约内存。所以本篇介绍的整数集合和压缩列表都是为了节约内存而存在的。那么,压缩列表的大致结构是什么?

压缩列表的大致结构

压缩列表是由一系列特殊编码的连续内存块组成的顺序型数据结构。一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组(字符串)或者一个整数值。

它的各个组成部分和说明如下(出自《Redis设计与实现第二版》第7章:压缩列表):

压缩列表更像是一种存储方式,和 Java 字节码中常量池的存储比较类似。感兴趣的可以去查一下。

压缩列表的节点主要由 previous_entry_length、encoding、content 三部分组成。如下图(出自《Redis设计与实现第二版》第7章:压缩列表):

  • previous_entry_length 表示压缩列表中前一个节点的长度,单位为字节。
  • encoding 记录了节点的 content 属性所保存数据的类型及长度。
  • content 则负责保存节点的值。可以使一个字节数组(字符串)或者整数。

Redis 学习笔记(篇四):整数集合和压缩列表的更多相关文章

  1. Redis学习笔记(四)集合进阶

    1.组合与关联多个集合 差集: SDIFF key1 [key2...](返回存在于key1但不存在其他集合中的元素) SDIFFSTORE destination key1 [key2...](将存 ...

  2. Redis底层探秘(四):整数集合及压缩列表

    整数集合 整数集合(intset)是集合键的底层实现之一,当一个集合只包含 整数值元素,并且这个集合的元素数量不多时,Redis就会使用郑书记和作为集合键的底层实现. 整数集合的实现 整数集合是red ...

  3. Redis数据结构—整数集合与压缩列表

    目录 Redis数据结构-整数集合与压缩列表 整数集合的实现 整数集合的升级 整数集合不支持降级 压缩列表的构成 压缩列表节点的构成 小结 Redis数据结构-整数集合与压缩列表 大家好,我是白泽.今 ...

  4. redis 笔记01 简单动态字符串、链表、字典、跳跃表、整数集合、压缩列表

    文中内容摘自<redis设计与实现> 简单动态字符串 1. Redis只会使用C字符串作为字面量,在大多数情况下,Redis使用SDS(Simple Dynamic String,简单动态 ...

  5. 【转】Redis学习笔记(四)如何用Redis实现分布式锁(1)—— 单机版

    原文地址:http://bridgeforyou.cn/2018/09/01/Redis-Dsitributed-Lock-1/ 为什么要使用分布式锁 这个问题,可以分为两个问题来回答: 为什么要使用 ...

  6. Redis学习笔记(四)——数据结构之List

    一.介绍 Redis列表(List)是简单的字符串列表,按照插入顺序排序.你可以添加一个元素到列表的头部(left)或者尾部(right),一个列表最多可以包含232-1个元素(4294967295, ...

  7. Redis 学习笔记(四)RDB 和 AOF 持久化机制

    一.Redis 持久化简介 Redis 的持久化功能是区别于 Memcached 显著特性,数据持久化可以保证系统在发生宕机和重启后数据不会丢失,对于 redis 这种存储在内存中的数据库显得尤为重要 ...

  8. Redis学习笔记(四)-数据类型之list类型

    redis的list类型其实就是一个每个子元素都是string类型的双向链表.所以[lr]push和[lr]pop命令的算法时间复杂度都是O(1).另外list会记录链表的长度.所以llen操作也是O ...

  9. Redis学习笔记(四) 基本命令:String操作

    原文链接:http://doc.redisfans.com/string/index.html append key value 将指定的值追加到key末尾,若key不存在,则创建并赋值,返回追加后的 ...

随机推荐

  1. intel edison with grove lcd

    由intel xdk,例如,下面的过程能够打印Hello world至grove lcd上 var mraa = require ('mraa'); var LCD = require ('jsupm ...

  2. GameBuilder见缝插针游戏开发系列(AA)

    今天推出了一款游戏叫<AA>.在最近IOS只是弹出一个游戏.非常心脏的孩子,但有很多乐趣.今天,我们谈论它tangide(GameBuilderV2.0)用控件UICanvas实现它. 在 ...

  3. HTML5 课程

    http://www.w3school.com.cn/html5/html_5_geolocation.asp HTML5 教程 HTML5 教程 HTML5 简单介绍 HTML5 视频 HTML5 ...

  4. CentOS6.5优盘安装

    从CentOS6.5开始直接把iso文件写入u盘就可实现优盘安装 windows平台:1.用UltraISO打开iso(如:CentOS-6.5-x86_64-bin-DVD1.iso)2.然后点“启 ...

  5. WPF ListView的使用

    <Window x:Class="XamlTest.Window14"        xmlns="http://schemas.microsoft.com/win ...

  6. miniui autocomplete支持放大镜按钮(data-grid)

    <style type="text/css"> html body .searchbox .mini-buttonedit-close { background:url ...

  7. CROSS JOIN

    原文:CROSS JOIN 最近在讲到T-SQL查询的Join部分时,一下子没有想起来CROSS JOIN的用法,因为其实平常也确实基本不用到.特意找了一个例子,以供参考 CROSS JOIN又称为笛 ...

  8. SQL Server Update:使用 TOP 限制更新的数据

    原文 使用 TOP 限制更新的数据 可以使用 TOP 子句来限制 UPDATE 语句中修改的行数.当 TOP (n) 子句与 UPDATE 一起使用时,将针对随机选择的 n 行执行删除操作.例如,假设 ...

  9. Android零基础入门第79节:Intent 属性详解(上)

    Android应用将会根据Intent来启动指定组件,至于到底启动哪个组件,则取决于Intent的各属性.本期将详细介绍Intent的各属性值,以及 Android如何根据不同属性值来启动相应的组件. ...

  10. IIS 设置文件可下载

    IIS遇到了文件不能下载的问题.为了让IIS能下载扩展名是INI的文件,我们需要如此操作:(括号内的是英文版本的名字) 打开“IIS管理器(InternetInformationServices(II ...