646 字
3 分钟
Redis 数据类型和底层编码有什么区别?
String、Hash、List、Set、ZSet 是面向命令使用者的逻辑类型;int、raw、listpack、hashtable 等是内部存储编码。同一种类型可以根据元素数量和长度选择不同编码,以减少小对象内存成本或提高大对象操作效率。 具体实现会随版本变化,本文以 Redis 7.2 的常见路径为例。
常见类型如何存储?
| 类型 | 常见内部形式 |
|---|---|
| String | 可用整数编码;短字符串可用 embstr;其他字符串常用 raw/SDS |
| Hash | 较小对象可用 listpack,超过配置条件转为哈希表 |
| List | 以 quicklist 组织节点,节点常使用 listpack 存放元素 |
| Set | 可用 intset、listpack 或哈希表,取决于版本和内容 |
| ZSet | 小对象可用 listpack,大对象常用字典与跳表配合 |
早期资料常把 Hash/ZSet 小对象说成 ziplist。Redis 7.x 的主流实现已经使用 listpack,不能跨版本背诵固定结论。Redis 7.2 也有小 Set 的 listpack 路径,因此“Set 永远只有 intset 与哈希表”不是所有版本都准确。
为什么不一直用紧凑编码?
listpack 把多个元素紧凑地放在连续内存中,减少指针和分配开销,也改善局部性。但查找或插入可能需要扫描、移动数据。元素少时节省内存更划算,元素多时则需要可扩展的数据结构。
可以用 TYPE key 查看逻辑类型,用 OBJECT ENCODING key 观察当前编码,用 MEMORY USAGE key 估算单 Key 的内存。转换阈值由类型相关配置控制;编码转换会改变成本,不应随意把阈值调得很大来追求内存数字好看。
常见追问
Hash 转成哈希表后,删小了会自动变回吗?
不能普遍假设自动回退。不同类型和版本转换策略不同,常见 Hash 增长转换不自动反向压缩;应观察实际编码。
embstr 和 raw 是两种不同业务类型吗?
不是,它们都属于 String,只是对象头与字符串存储的内存组织方式不同,命令语义仍由 String 类型定义。
ZSet 为什么同时需要字典和跳表?
字典方便按成员查分数,跳表方便按分数排序、排名与范围遍历。两种结构服务于不同访问路径。
知道编码对项目有什么帮助?
可以解释大量小对象的内存开销、编码转换后的延迟变化,以及为什么一个巨大 Hash 并不总比拆分后的 Key 更合适。
Redis 数据类型和底层编码有什么区别?
https://blog.xqcherry.top/posts/interview/redis/redis-internal-encodings/ 目录