Redis数据结构:Hash类型全面解析
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
Redis作为一个开源的、内存中的数据结构存储系统以其出色的性能和灵活的数据类型广泛应用于缓存、消息队列、发布订阅系统等多种场景。在 Redis 的五种基本数据类型中Hash 类型是一种非常重要的数据类型。它可以存储键值对的集合且能够用小于1毫秒的时间复杂度进行添加、删除、更新和查找操作因此在实际应用中有着广泛的用途。
在接下来的文章中我将详细介绍 Redis 的 Hash 类型包括它的内部实现、主要特性、常用命令以及应用场景。无论你是刚接触 Redis 的新手还是已经有一定经验的开发者我相信你都能从这篇文章中学到一些有用的知识。让我们一起深入了解 Redis 的 Hash 类型探索它的魅力所在。
文章目录
1、Redis-Hash数据类型
1.1、Redis-Hash类型简介
Redis 的 Hash 类型是一种键值对集合这种数据类型适合用于存储对象。在 Hash 类型中每个键都有一个对应的值这和 Python 的字典、Java 的 HashMap 以及 JavaScript 的对象非常相似。
以下是 Redis Hash 类型的一些主要特性
-
键值对集合Hash 类型可以存储多个键值对每个键都有一个对应的值。
-
二进制安全Hash 类型的键和值都是二进制安全的这意味着它们可以包含任何数据包括二进制数据。
-
大容量单个 Hash 类型可以存储超过 4 亿个键值对。
-
高效的查找速度无论 Hash 中存储了多少数据查找某个键的速度都非常快。
1.2、Redis-Hash应用场景
Redis 的 Hash 类型是一种键值对集合适合用于存储对象因此在很多场景下都有着广泛的应用。以下是一些常见的应用场景
-
存储对象Hash 类型可以存储多个键值对非常适合用于存储对象。例如你可以使用 Hash 类型存储用户的信息如用户名、密码、邮箱等
-
数据分析你可以使用 Hash 类型存储各种统计数据例如用户的行为数据然后进行数据分析
-
社交网络在社交网络应用中你可以使用 Hash 类型存储用户的朋友列表、粉丝列表等
以上只是一些常见的应用场景实际上由于 Redis 的灵活性你可以根据自己的需求将 Redis 的 Hash 类型应用在更多的场景中。
2、Redis-Hash底层结构
2.1、Redis-Hash底层结构介绍
Redis 的 Hash 类型的底层实现是一个非常优化的数据结构它会根据实际情况选择使用紧凑的压缩列表ziplist或者散列表hashtable作为底层实现。
Redis 的 Hash 类型会根据实际情况在压缩列表ziplist和散列表hashtable之间进行切换这主要取决于两个配置参数hash-max-ziplist-entries
和 hash-max-ziplist-value
。
hash-max-ziplist-entries
这个参数用于设置压缩列表可以存储的最大节点数量。如果一个 Hash 类型的元素数量超过这个值那么就会从压缩列表切换到散列表。默认值为 512hash-max-ziplist-value
这个参数用于设置压缩列表中每个节点的最大值大小以字节为单位。如果一个 Hash 类型的任何元素的大小超过这个值那么就会从压缩列表切换到散列表。默认值为 64。
这两个参数都可以在 Redis 的配置文件中进行设置。通过调整这两个参数你可以根据自己的应用特性选择更倾向于节省内存还是更倾向于提高性能。
- 从压缩列表转换到散列表当 Hash 类型存储的字段和值的数量超过
hash-max-ziplist-entries
的值或者任何字段或值的大小超过hash-max-ziplist-value
的值时Redis 会将底层结构从压缩列表转换为散列表。这个过程是自动进行的对用户来说是透明的。 - 从散列表转换到压缩列表然而一旦 Hash 类型的底层结构被转换为散列表就无法再转换回压缩列表。这是因为散列表的性能更高而且在大多数情况下一旦一个 Hash 类型的大小超过了一定的阈值那么它的大小就很可能会继续增长。
2.2、Redis-压缩列表ziplist
当 Hash 类型存储的字段和值的数量较少且字段和值的字符串长度较短时Redis 会选择使用压缩列表作为底层实现。压缩列表是一种为节省内存而设计的特殊编码结构它将所有的字段和值紧凑地存储在一起。这种方式的优点是占用内存少但是在需要修改数据时可能需要对整个压缩列表进行重写性能较低。
Redis 的压缩列表ziplist是一种特殊的编码结构它被设计用来节省内存。压缩列表将所有的元素紧凑地存储在一起每个元素都只占用连续的内存空间。
一个压缩列表的结构如下
+---------+---------+--------+---------+---------+---------+--------+
| zlbytes | zltail | zllen | entry_1 | entry_2 | ... | zlend |
+---------+---------+--------+---------+---------+---------+--------+
Ps在 Redis 的源代码中压缩列表ziplist的结构并没有直接定义为一个 C 结构体而是通过一系列的宏和函数来操作一段连续的内存。
属性 | 说明 |
---|---|
“zlbytes” | 一个 4 字节的整数表示整个压缩列表占用的字节数量包括 <zlbytes> 自身的大小。 |
“zltail” | 一个 4 字节的整数表示压缩列表中最后一个元素的偏移量。这个偏移量是相对于整个压缩列表的起始地址的。 |
“zllen” | 一个 2 字节的整数表示压缩列表中的元素数量。如果元素数量超过 65535那么这个值就会被设定为 65535需要遍历整个压缩列表才能获取到实际的元素数量。 |
“entry” | 压缩列表中的元素每个元素都由一个或多个字节组成。每个元素的第一个字节又称为"entry header"用于表示这个元素的长度以及编码方式。 |
“zlend” | 一个字节值为 255表示压缩列表的结束。 |
2.3、Redis-散列表hashtable
当 Hash 类型存储的字段和值的数量较多或者字段和值的字符串长度较长时Redis 会选择使用散列表作为底层实现。散列表是一种常见的键值对映射结构它通过一个散列函数将键映射到一个桶中然后在桶中进行查找。这种方式的优点是查找和修改数据的性能较高但是占用的内存也较多。
Redis 的散列表hash table是一种常见的键值对映射结构它通过一个散列函数将键映射到一个桶中然后在桶中进行查找。Redis 的散列表使用链表法解决哈希冲突即当多个键映射到同一个桶时将它们存储在同一个链表中。
在 Redis 的源代码中散列表的结构定义如下
typedef struct dictEntry {
void *key;
void *val;
struct dictEntry *next;
} dictEntry;
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
typedef struct dict {
dictht ht[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
int iterators; /* number of iterators currently running */
} dict;
其中
-
dictEntry
结构体表示散列表中的一个节点包含键key
、值val
和指向下一个节点的指针next
。 -
dictht
结构体表示一个散列表包含指向哈希表数组的指针table
、哈希表数组的大小size
、哈希表数组大小掩码sizemask
和已使用的节点数量used
。 -
dict
结构体表示一个字典包含两个散列表ht
、当前进行 rehash 的索引rehashidx
和当前运行的迭代器数量iterators
。
这就是 Redis 散列表的结构。
3、Hash 常用命令
以下是 Redis 中与 Hash 类型相关的一些命令
3.1、设置Hash值
Redis 中设置 Hash 值的命令是 HSET
它的语法如下
HSET key field value
其中key
是哈希表的名称field
是哈希表中的字段名value
是字段对应的值。如果哈希表中原本不存在该字段则会创建一个新的字段并将其值设置为指定的值。如果该字段已经存在则会覆盖原有的值。
例如我们可以使用以下命令设置一个名为 user:1001
的哈希表中的字段 name
的值为 Alice
HSET user:1001 name Alice
如果需要同时设置多个字段的值可以使用 HMSET
命令它的语法如下
HMSET key field1 value1 [field2 value2 ...]
例如我们可以使用以下命令同时设置 user:1001
哈希表中的 name
和 age
字段的值
HMSET user:1001 name Alice age 25
这样就可以一次性设置多个字段的值了。
在 Redis 中获取 Hash 值的命令是 HGET
它的语法如下
HGET key field
其中key
是哈希表的名称field
是哈希表中的字段名。
例如我们可以使用以下命令获取一个名为 user:1001
的哈希表中的字段 name
的值
HGET user:1001 name
3.2、获取Hash值
如果需要获取哈希表中的多个字段的值可以使用 HMGET
命令它的语法如下
HMGET key field1 [field2 ...]
例如我们可以使用以下命令获取 user:1001
哈希表中的 name
和 age
字段的值
HMGET user:1001 name age
如果需要获取哈希表中所有的字段和值可以使用 HGETALL
命令它的语法如下
HGETALL key
例如我们可以使用以下命令获取 user:1001
哈希表中的所有字段和值
HGETALL user:1001
3.3、删除Hash值
在 Redis 中删除 Hash 值的命令是 HDEL
它的语法如下
HDEL key field [field ...]
其中key
是哈希表的名称field
是要删除的字段名。你可以一次删除一个或多个字段。
例如我们可以使用以下命令删除一个名为 user:1001
的哈希表中的字段 name
HDEL user:1001 name
如果你想要删除多个字段可以在命令后面依次列出这些字段的名字例如
HDEL user:1001 name age
这个命令会删除 user:1001
哈希表中的 name
和 age
字段。
需要注意的是HDEL
命令只会删除指定的字段及其值而不会删除整个哈希表。如果你想要删除整个哈希表可以使用 DEL
命令例如
DEL user:1001
这个命令会删除整个 user:1001
哈希表。
3.4、其他Hash命令
Redis 中 Hash 其他的一些常用命令还有
HEXISTS key field
查看哈希表 key 中指定的字段是否存在。HLEN key
获取哈希表中字段的数量。HKEYS key
获取所有哈希表中的字段。HVALS key
获取哈希表中所有值。HGETALL key
获取在哈希表中指定 key 的所有字段和值。HINCRBY key field increment
为哈希表 key 中的指定字段的整数值加上增量 increment 。HINCRBYFLOAT key field increment
为哈希表 key 中的指定字段的浮点数值加上增量 increment 。HMSET key field value [field value ...]
同时将多个 field-value (字段-值)对设置到哈希表的 key 中。HMGET key field [field ...]
获取所有给定字段的值。
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |