同整数集合同样压缩列表也不是基础数据结构,而是 Redis 本身设计的一种数据存储结构。它有点儿相似数组,经过一片连续的内存空间,来存储数据。不过,它跟数组不一样的一点是,它容许存储的数据大小不一样。html
听到“压缩”两个字,直观的反应就是节省内存。之因此说这种存储结构节省内存,是相较于数组的存储思路而言的。咱们知道,数组要求每一个元素的大小相同,若是咱们要存储不一样长度的字符串,那咱们就须要用最大长度的字符串大小做为元素的大小(假设是20个字节)。存储小于 20 个字节长度的字符串的时候,便会浪费部分存储空间。redis
数组的优点占用一片连续的空间能够很好的利用CPU缓存访问数据。若是咱们想要保留这种优点,又想节省存储空间咱们能够对数组进行压缩。数组
可是这样有一个问题,咱们在遍历它的时候因为不知道每一个元素的大小是多少,所以也就没法计算出下一个节点的具体位置。这个时候咱们能够给每一个节点增长一个lenght的属性。缓存
如此。咱们在遍历节点的以后就知道每一个节点的长度(占用内存的大小),就能够很容易计算出下一个节点再内存中的位置。这种结构就像一个简单的压缩列表了。数据结构
压缩列表(zip1ist)是列表和哈希的底层实现之一。运维
当一个列表只包含少许列表项,而且每一个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来作列表的底层实现。编码
当一个哈希只包含少许键值对,比且每一个键值对的键和值要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来作哈希的底层实现。设计
压缩列表是Redis为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型(sequential)数据结枃。一个压缩列表能够包含任意多个节点(entry),每一个节点能够保存一个字节数组或者一个整数值,以下图。指针
示例:htm
如上图,展现了一个总长为80字节,包含3个节点的压缩列表。若是咱们有一个指向压缩列表起始地址的指针p,那么表为节点的地址就是P+60。
每一个压缩列表节点能够保存一个字节数组或者一个整数值。其中,字节数组能够是如下三种长度中的一种。
整数值能够是如下6种长度中的一种
节点的 previous_entry_length属性以字节为单位,记录了压缩列表中前一个节点的长度。 previous_entry_length属性的长度能够是1字节或者5字节。
节点的encoding属性记录了节点的content属性所保存数据的类型以及长度。
节点的content属性负责保存节点的值,节点值能够是一个字节数组或者整数,值的类型和长度由节点的encoding属性决定。
操做 | 时间复杂度 |
---|---|
建立一个新的压缩列表 | O(1) |
建立一个包含给定值的新节点,并将这个新节点添加到压缩列表的表头或者表尾 | 平均O(N),最坏O(N^2)(可能发生连锁更新) |
将包含给定值的新节点插人到给定节点以后 | 平均O(N),最坏O(N^2)(可能发生连锁更新) |
返回压缩列表给定索引上的节点 | O(N) |
在压缩列表中査找并返回包含了给定值的节点 | 由于节点的值多是一个字节数组,因此检查节点值和给定值是否相同的复杂度为O(N),而查找整个列表的复杂度则为(N^2) |
返回给定节点的下一个节点 | O(1) |
返回给定节点的前一个节点 | O(1) |
获取给定节点所保存的值 | O(1) |
从压缩列表中删除给定的节点 | 平均O(N),最坏O(N^2)(可能发生连锁更新) |
删除压缩列表在给定索引上的连续多个 | 平均O(N),最坏O(N^2)(可能发生连锁更新) |
返回压缩列表目前占用的内存字节数 | O(1) |
返回压缩列表目前包含的节点数量 | 点数量小于65535时为O(1),大于65535时为O(N) |
压缩列表是Redis为节约内存本身设计的一种顺序型数据结构。
添加新节点到压缩列表,或者从压缩列表中删除节点,可能会引起连锁更新操做,但这种操做出现的概率并不高。
《Redis设计与实现》
《Redis开发与运维》
《Redis官方文档》