Redis 哈希(Hash)
Redis 哈希是一个键值对集合,适用于存储对象。每个哈希是一个键与多个字段及其值的映射。哈希非常适合用于表示具有多个属性的对象,如用户信息。
场景示例
-
存储和获取用户信息
- 示例:
HSET user:1000 name "Alice" age "30" email "alice@example.com" HGETALL user:1000
- 说明:使用
HSET
命令存储用户信息,并使用HGETALL
获取所有字段和值。
- 示例:
-
更新特定字段
- 示例:
HSET user:1000 age "31" HGET user:1000 age
- 说明:使用
HSET
更新用户的年龄,并使用HGET
获取特定字段的值。
- 示例:
-
删除字段
- 示例:
HDEL user:1000 email HGETALL user:1000
- 说明:使用
HDEL
删除用户的 email 字段,并使用HGETALL
获取所有字段和值。
- 示例:
-
字段存在性检查
- 示例:
HEXISTS user:1000 email
- 说明:使用
HEXISTS
检查某字段是否存在。
- 示例:
-
获取所有字段
- 示例:
HKEYS user:1000
- 说明:使用
HKEYS
获取所有字段名称。
- 示例:
-
获取所有值
- 示例:
HVALS user:1000
- 说明:使用
HVALS
获取所有字段的值。
- 示例:
-
增加字段值
- 示例:
HINCRBY user:1000 age 1 HGET user:1000 age
- 说明:使用
HINCRBY
增加字段的数值,并使用HGET
获取字段的值。
- 示例:
底层实现
Redis 哈希底层实现主要基于两种数据结构:ziplist
(压缩列表)和 hashtable
(哈希表)。
-
压缩列表(ziplist)
- 当哈希包含的键值对数量较少且每个键值对的长度较短时,Redis 使用压缩列表存储哈希。压缩列表是一种经过特殊编码的连续内存块,节省空间。
- 结构:
struct { unsigned int zlbytes; // 压缩列表的总字节数 unsigned int zltail; // 到达表尾的偏移量 unsigned int zllen; // 压缩列表包含的节点数量 unsigned char entries[]; // 数据节点 };
- 优点:紧凑内存布局,适合存储小数据量。
-
哈希表(hashtable)
- 当哈希包含的键值对数量较多或某些键值对的长度较长时,Redis 使用哈希表存储哈希。哈希表提供快速的查找、插入和删除操作。
- 结构:
typedef struct dictht { dictEntry **table; // 哈希表数组 unsigned long size; // 哈希表大小 unsigned long sizemask; // 哈希表大小掩码,用于计算索引 unsigned long used; // 已使用节点数量 } dictht; typedef struct dictEntry { void *key; // 键 void *val; // 值 struct dictEntry *next; // 链表指针,解决冲突 } dictEntry;
- 优点:高效处理大数据量和长字符串。
Redis 通过内存占用和访问速度的权衡,选择最合适的数据结构来存储哈希数据。开始时,Redis 使用压缩列表存储小型哈希,当哈希增长到一定规模时,自动转换为哈希表,从而兼顾空间效率和性能。