整数集合的紧凑编码
当集合中所有成员都是整数、且数量不超过 set-max-intset-entries(默认 512)时,Redis 会用 intset 存储:把元素按数值升序放在一段连续内存里,查找走二分。相比哈希表实现,每个成员省掉了指针与哈希桶的开销,小集合上的内存差距相当明显。但两个条件任一被打破,编码就会永久转换为 hashtable,而且不会自动转回来。
基本信息
| 编码路径 | intset 转换为 hashtable,单向 |
|---|---|
| 阈值 | set-max-intset-entries,默认 512 |
| 查找方式 | 有序数组上的二分查找 |
| 转换触发 | 插入非整数成员,或成员数超出阈值 |
| 查看方式 | OBJECT ENCODING 返回 intset 或 hashtable |
典型使用场景
- 用集合存用户 ID、设备 ID 等纯整数标识,确认编码是否仍是 intset
- 内存敏感场景评估整数集合相对哈希表能省多少
- 上线前评估是否有非整数成员会污染编码
- 排查集合内存突然上升:编码已经从 intset 转成 hashtable
- 调阈值之前先量化单键占用的变化
查看与触发
查看与触发
redis-cli SADD ids 101 102 103
redis-cli OBJECT ENCODING ids # intset
redis-cli MEMORY USAGE ids # 量化占用,便于前后对比
redis-cli SADD ids abc # 插入非整数成员
redis-cli OBJECT ENCODING ids # 已经变成 hashtable
redis-cli CONFIG GET set-max-intset-entries触发转换的条件
| 条件 | 结果 | 说明 |
|---|---|---|
| 成员数超出阈值 | 转 hashtable | 默认 512,可按内存与操作特征调整 |
| 插入非整数成员 | 永久转 hashtable | 删掉该成员也不会转回 |
| 成员超出 64 位整数范围 | 转 hashtable | 超大数值不被视为整数成员 |
| 新建纯整数集合 | 保持 intset | 新增元素可能触发数组扩容重排 |
intset 内部按数值升序存放,插入新元素可能需要整块数组扩容重排,元素越多单次插入要搬动的字节越多。这是它用内存紧凑性换来的代价,元素数量大时要留意插入延迟。
编码转换是单向的:一旦变成 hashtable,即使把非整数成员删掉、成员数降回阈值以内,也不会自动回到 intset,必须把这个键重建一遍。
内存收益可以用 MEMORY USAGE 直接量化:同样规模的纯整数集合,紧凑编码与哈希表编码的差值通常在数倍量级。评估是否要调整阈值时,用真实业务的键做前后对比,比按理论模型估算可靠得多。