bigywater.tech
Redis · 11

IntSet 的升级过程

验证一个纯整数set加非整数成员的转换路径,跟纯整数但数量超限的转换路径,看intset是怎么走向两种不同结局的。

类型不纯→listpack
混入非整数触发的转换
数量超限→hashtable
纯整数但超数量触发的转换(跳过listpack)
同起点不同终点
两种原因导向不同的目标结构

做的事:一个纯整数的set,触发两种不同的升级方式

intset是专门为"全是整数"的set设计的紧凑编码。

操作SADD myset 1 2 3 OBJECT ENCODING myset SADD myset "hello" -- 加入一个非整数成员 OBJECT ENCODING myset

验证:加一个非整数成员,intset立刻变成listpack

结果确认了intset的"纯度"要求。

结果SADD myset 1 2 3 OBJECT ENCODING myset → :intset SADD myset "hello" OBJECT ENCODING myset → :listpack(不是intset了!)

intset要求集合里所有成员都必须是整数——只要混入一个字符串,哪怕集合本身还很小,Redis也会立刻把它转换成通用的 listpack 编码(能存任意类型),不会因为大部分还是整数就继续用intset硬撑。

验证:超过数量上限,走的是另一条不同的路

如果一直全是整数,只是数量超过了阈值,会转成listpack还是别的?

结果(set-max-intset-entries设成128)SADD 128个纯整数 OBJECT ENCODING → :intset SADD 第129个纯整数 OBJECT ENCODING → :hashtable(不是listpack!)

这里走的是跟"混入非整数"完全不同的路径:数量超限但全是整数时,Redis直接跳过listpack,一步转成 hashtable。原因是:intset的设计目标就是"大量纯整数还能保持紧凑",一旦数量多到要放弃intset,说明这个集合本来就偏大,listpack这种同样是连续内存的紧凑结构在数据量大时不划算(插入/查找退化成线性扫描),所以直接一步到位用哈希表。

两条不同的升级路径反映的是两种不同的"不适合intset":混入非整数是"类型不纯",转向同样紧凑但更通用的listpack;数量超限是"体量太大",转向真正为大数据量设计的hashtable。同一个起点(intset),因为不同的原因走向了不同的终点。

分步演示:intset的两条升级路径

每一步都是本文上面用redis-cli跑出来的原始结果。

intset有两条不同原因触发的升级路径
这一步新验证的场景

    本文用到的工具

    • 本机 Redis 8.10.1 单节点
    • OBJECT ENCODING / CONFIG SET set-max-intset-entries:对比两种升级路径
    京ICP备2026067502号-1京公网安备11010502063487号