Redis的ZipList、SkipList和ListPack之间的区别
将这三种数据结构放在一起比较,是因为它们都是 Redis 实现 ZSet 的核心数据结构。
在Redis 7.0之前,ZSet 主要采用 ZipList 和 SkipList 两种结构实现。而自Redis 7.0起,ZipList被ListPack取代,因此当前ZSet的核心实现变为ListPack和SkipList。
其中SkipList是长期存在的实现方式,我们先来看它的特性。
SkipList(跳表)
跳表是一种基于链表的多层索引结构,通过在基础链表上增加多级索引来提升查询效率。相比普通链表,跳表能够在 O(log N) 时间复杂度内完成查找、插入和删除操作,并支持高效的范围查询(如 ZRANGEBYSCORE 等命令)。
优势:
- 所有核心操作(插入/删除/查找)的时间复杂度均为O(log N)
- 特别适合范围查询场景
不足:
- 内存占用较高(需要维护多级指针)
ZipList(压缩列表)
ZipList采用连续内存存储方式,所有元素紧密排列,在小数据量时能显著减少内存使用。
优势:
- 内存利用率极高(紧凑存储)
- 适合小规模数据存储
不足:
- 查询、插入和删除都是O(N)时间复杂度
- 存在级联更新风险
正是由于这些特性差异,Redis 会在元素较少时使用 ZipList,数据量增大后自动转换为 SkipList。
ListPack(紧凑列表)
ListPack 是Redis 5.0引入的新型高效数据结构(7.0+版本正式替代 ZipList ),专为解决 ZipList 和 SkipList 的某些局限性而设计。
特点:
- 适用于小型有序集合、列表和哈希
- 比 ZipList 更灵活、适应性更强
- 完美规避了级联更新问题
对比总结
特性 | SkipList | ZipList | ListPack |
---|---|---|---|
设计目标 | 高效范围查询 | 内存紧凑 | 解决级联更新 |
内存布局 | 多层链表 | 连续内存块 | 连续内存块 |
查询复杂度 | O(log N) | O(n) | O(n) |
插入复杂度 | O(log N) | O(1)~O(n²) | O(1) |
删除复杂度 | O(log N) | O(1)~O(n²) | O(1) |
内存占用 | 高 | 低 | 极低 |
版本支持 | 全版本 | ≤6.2 | ≥5.0 (7.0+默认) |
核心优势 | 有序访问高效 | 小数据内存优化 | 无级联更新 |
主要缺点 | 内存占用高 | 级联更新 | 范围查询效率低 |
适用场景 | 有序集合(ZSet) | 小型Hash/Set/ZSet | 全类型小规模存储 |