笔记摘抄自 https://pdai.tech/md/db/nosql-redis/db-redis-data-type-enc.html
redisObject 查看编码命令
set k1 1
object encoding k1
set k2 hello
object encoding k2
字符串对象
字符串是redis 最基本的数据类型,不仅所有的key都是字符串类型,其他几种数据类型构成的元素也是字符串,字符串的长度不能超过512M。
-
编码
字符串对象的编码可以是 int, raw 或者 embstr. -
int 编码: 保存的可以是用long 类型表示的整数值
-
embstr 编码: 保存长度小于44字节的字符串
-
raw 编码: 保存长度大于44字节的字符串
-
raw 和 embstr 的区别
embstr 使用只分配一次内存空间,而raw需要分配两次内存空间。因此与raw相比,embstr 的好处在于创建时少分配一次空间,删除时少释放一次空间,以及对象的所有数据连在一起,寻找方便。而embstr 的坏处很明显,字符串的长度增加需要重新分配内存时,整个redisObject对象和sds都需要重新分配空间
ps: redis中对于浮点数类型也是作为字符串保存的,在需要的时候在转换
- 编码的转换
当int 编码保存的值不再是整数,或者大小超过long的范围时,自动转为raw.
对于embstr 编码,由于redis 没有任何的修改程序,在对embstr修改时,都会先转为raw在进行修改,因此,只要是修改embstr对象,修改后的对象一定是raw,无论是否达到了44个字节
列表对象
- 编码
列表对象的编码是quicklist - 内存布局
哈希对象
哈希对象的键是一个字符串类型,值是一个键值对集合
- 编码
哈希对象的编码可以是ziplist 或者 hashtable;对应的底层实现有两种,一种是ziplist ,一种是dict - 编码转换
同事满足下面两个条件是,使用ziplist编码:
- 列表保存元素小于512个
- 每个元素长度小于64字节
不能满足这两个条件的时候使用hashtable编码。以上两个条件可以通过redis配置文件 zset-max-ziplist-entries 和 zset-max-ziplist-value 进行修改
集合对象
集合对象set是string类型的无序集合。与列表的区别:集合中的元素是无序的,因此不能通过索引来操作元素,集合中的原始不能有重复。
- 编码
intset 或者 hashtable ,底层实现有两种,分别是intset 和 dict。显然intset作为底层实现的数据结构时,集合中存储的只能是数值数据,而且必须是整数;使用dict作为底层实现时,是将数据全部存储于dict的键中,值字段闲置不用 - 编码转换
当集合同时满足以下两个条件时,使用intset 编码:
- 集合对象所有元素都是整数
- 结合对象所有元素数量不超过512
不能满足这两个条件的就是用hashtable编码。第二个条件可以通过配置文件的 set-max-intset-entries 进行配置
有序集合对象
和上面的集合对象相比,有序集合对象是有序的。与列表使用索引下表作为排序依据不同,有序集合为每个元素设置一个分数作为排序依据
- 编码
有序集合的底层实现有两种,一种是使用ziplist最为底层实现,另一种比较特殊,底层使用了两种数据结构:dict 与 skiplist。前者对应的编码值为ZIPLIST,后者为SKIPLIST
其实有序集合单独使用字典或者跳跃表其中一种数据结构都可以实现,但是这里使用两种数据结构组合起来,原因是假如单独使用字典,虽然能以O(1)的时间复杂度查找成员的分值,但是因为字典是无序的方式来保存集合元素,所以每次进行范围操作的时候都要进行排序;假如单独使用跳跃表来实现,虽然能执行范围操作,但是查找操作由O(1)的复杂度变为了O(logN)。 - 编码转换
当有序集合对象同时满足以下两个条件时,对象使用ziplist编码:
- 保存的元素数量小于128;
- 保存的所有元素长度都小于64字节
不满足上面两个条件使用skiplist编码。以上两个条件可以通过配置文件 zset-max-ziplist-entries 选项和 zset-max-ziplist-value 进行修改