Hash比String存对象更省内存,因Hash共享字段名并采用ziplist/hashtable压缩编码,实测省40%–60%;String则重复存储key、引号、逗号等冗余字符。

为什么 Hash 比 String 存对象更省内存
直接存 JSON 字符串到 String 类型,每个字段都带 key 名、引号、逗号、空格——这些全算内存。而 HASH 把字段名和值分别编码,复用字段名(比如 1000 个用户都有 name、age),底层用 ziplist 或 hashtable 压缩存储,实测能省 40%–60% 内存。
关键不是“结构好看”,是 Redis 对 HASH 的字段名做了共享前缀和紧凑编码,String 则完全没这层优化。
什么时候该用 HASH 而不是 JSON String
满足以下任一条件,就该切到 HASH:
- 对象字段固定且数量少(如
user:{id}含name/email/status) - 需要频繁读写单个字段(
HGET user:123 name比GET user:123再解析 JSON 快得多) - 要批量更新几个字段但不想反序列化/序列化整条 JSON(
HMSET user:123 name "a" status "active") - 字段值普遍较短(
ziplist编码生效阈值默认hash-max-ziplist-entries 512+hash-max-ziplist-value 64)
如果字段名不固定、嵌套深(如 address.city)、或单字段超 64 字节且数量多,ziplist 会退化为 hashtable,优势减弱。
必须调的两个配置项:避免 ziplist 过早退化
默认配置在字段稍长或稍多时就触发 hashtable,失去压缩优势。上线前务必检查:
-
hash-max-ziplist-entries:建议设为1024(别盲目调太高,超过后内存反而涨) -
hash-max-ziplist-value:建议设为128或256(字段值平均长度 × 1.5 是较安全的起点)
改完要 CONFIG REWRITE 持久化,并用 DEBUG OBJECT key 看编码是否仍是 ziplist。常见坑:只改了 redis.conf 但没 CONFIG REWRITE,重启后失效。
HGETALL 的代价比你想的高
它把整个 HASH 拉成数组返回,网络+客户端解析开销大,尤其字段多时。别把它当 SELECT * 用:
- 只读一个字段 → 用
HGET - 读多个已知字段 → 用
HMGET - 真要全量 → 确认客户端能流式处理,且业务允许延迟
更隐蔽的坑:HGETALL 在 ziplist 编码下需遍历解码全部字段,CPU 消耗比 hashtable 还高一点。字段数 > 100 时,响应时间可能抖动明显。
字段多又常要全量?不如拆成主信息(HASH)+ 扩展信息(独立 String 或 JSON),按需加载。

















