Redis开发与运维. 2.3 哈希

简介:

2.3 哈希

几乎所有的编程语言都提供了哈希(hash)类型,它们的叫法可能是哈希、字典、关联数组。在Redis中,哈希类型是指键值本身又是一个键值对结构,形如value={{field1,value1},...{fieldN,valueN}},Redis键值对和哈希类型二者的关系可以用图2-14来表示。

 

图2-14 字符串和哈希类型对比

哈希类型中的映射关系叫作field-value,注意这里的value是指field对应的值,不是键对应的值,请注意value在不同上下文的作用。

2.3.1 命令

(1)设置值

hset key field value

下面为user:1添加一对field-value:

127.0.0.1:6379> hset user:1 name tom?

(integer) 1

如果设置成功会返回1,反之会返回0。此外Redis提供了hsetnx命令,它们的关系就像set和setnx命令一样,只不过作用域由键变为field。

(2)获取值

hget key field

例如,下面操作获取user:1的name域(属性)对应的值:

127.0.0.1:6379> hget user:1 name?

"tom"

如果键或field不存在,会返回nil:

127.0.0.1:6379> hget user:2 name?

(nil)?

127.0.0.1:6379> hget user:1 age?

(nil)

(3)删除field

hdel key field [field ...]

hdel会删除一个或多个field,返回结果为成功删除field的个数,例如:

127.0.0.1:6379> hdel user:1 name?

(integer) 1

127.0.0.1:6379> hdel user:1 age?

(integer) 0

(4)计算field个数

hlen key

例如user:1有3个field:

127.0.0.1:6379> hset user:1 name tom?

(integer) 1?

127.0.0.1:6379> hset user:1 age 23

(integer) 1?

127.0.0.1:6379> hset user:1 city tianjin

(integer) 1

127.0.0.1:6379> hlen user:1

(integer) 3

(5)批量设置或获取field-value

hmget key field [field ...]?

hmset key field value [field value ...]

hmset和hmget分别是批量设置和获取field-value,hmset需要的参数是key和多对field-value,hmget需要的参数是key和多个field。例如:

127.0.0.1:6379> hmset user:1 name mike age 12 city tianjin

OK?

127.0.0.1:6379> hmget user:1 name city

1) "mike"

2) "tianjin"

(6)判断field是否存在

hexists key field

例如,user:1包含name域,所以返回结果为1,不包含时返回0:

127.0.0.1:6379> hexists user:1 name

(integer) 1

(7)获取所有field

hkeys key

hkeys命令应该叫hfields更为恰当,它返回指定哈希键所有的field,例如:

127.0.0.1:6379> hkeys user:1

1) "name"?

2) "age"?

3) "city"

(8)获取所有value

hvals key

下面操作获取user:1全部value:

127.0.0.1:6379> hvals user:1?

1) "mike"?

2) "12"?

3) "tianjin"

(9)获取所有的field-value

hgetall key

下面操作获取user:1所有的field-value:

127.0.0.1:6379> hgetall user:1

1) "name"

2) "mike"

3) "age"

4) "12"

5) "city"

6) "tianjin"

在使用hgetall时,如果哈希元素个数比较多,会存在阻塞Redis的可能。如果开发人员只需要获取部分field,可以使用hmget,如果一定要获取全部field-value,可以使用hscan命令,该命令会渐进式遍历哈希类型,hscan将在2.7节介绍。

(10)hincrby hincrbyfloat

hincrby key field

hincrbyfloat key field

hincrby和hincrbyfloat,就像incrby和incrbyfloat命令一样,但是它们的作用域是filed。

(11)计算value的字符串长度(需要Redis 3.2以上)

hstrlen key field

例如hget user:1 name的value是tom,那么hstrlen的返回结果是3:

127.0.0.1:6379> hstrlen user:1 name

(integer) 3

表2-3是哈希类型命令的时间复杂度,开发人员可以参考此表选择适合的命令。

表2-3 哈希类型命令的时间复杂度

命  令         时间复杂度

hset key field value  O(1)

hget key field   O(1)

hdel key field [field ...]      O(k),k是field个数

hlen key   O(1)

hgetall key        O(n),n是field总数

hmget field [field ...]         O(k),k是field的个数

hmset field value [field value ...]      O(k),k是field的个数

hexists key field        O(1)

hkeys key O(n),n是field总数

hvals key  O(n),n是field总数

hsetnx key field value       O(1)

hincrby key field increment      O(1)

hincrbyfloat key field increment      O(1)

hstrlen key field        O(1)?

 

2.3.2 内部编码

哈希类型的内部编码有两种:

ziplist(压缩列表):当哈希类型元素个数小于hash-max-ziplist-entries配置(默认512个)、同时所有值都小于hash-max-ziplist-value配置(默认64字节)时,Redis会使用ziplist作为哈希的内部实现,ziplist使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀。

hashtable(哈希表):当哈希类型无法满足ziplist的条件时,Redis会使用hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降,而hashtable的读写时间复杂度为O(1)。

下面的示例演示了哈希类型的内部编码,以及相应的变化。

1)当field个数比较少且没有大的value时,内部编码为ziplist:

127.0.0.1:6379> hmset hashkey f1 v1 f2 v2

OK

127.0.0.1:6379> object encoding hashkey

"ziplist"

2.1)当有value大于64字节,内部编码会由ziplist变为hashtable:

127.0.0.1:6379> hset hashkey f3 "one string is bigger than 64 byte...忽略..."

OK

127.0.0.1:6379> object encoding hashkey

"hashtable"

2.2)当field个数超过512,内部编码也会由ziplist变为hashtable:

127.0.0.1:6379> hmset hashkey f1 v1 f2 v2 f3 v3 ...忽略... f513 v513

OK

127.0.0.1:6379> object encoding hashkey

"hashtable"

有关哈希类型的内存优化技巧将在8.3节中详细介绍。

2.3.3 使用场景

图2-15为关系型数据表记录的两条用户信息,用户的属性作为表的列,每条用户信息作为行。

如果将其用哈希类型存储,如图2-16所示。

相比于使用字符串序列化缓存用户信息,哈希类型变得更加直观,并且在更新操作上会更加便捷。可以将每个用户的id定义为键后缀,多对field-value对应每个用户的属性,类似如下伪代码:

UserInfo getUserInfo(long id){?

    // 用户id作为key后缀

    userRedisKey = "user:info:" + id;

    // 使用hgetall获取所有用户信息映射关系

    userInfoMap = redis.hgetAll(userRedisKey);

    UserInfo userInfo;?

    if (userInfoMap != null) {?

        // 将映射关系转换为UserInfo

        userInfo = transferMapToUserInfo(userInfoMap);?

    } else {

        // 从MySQL中获取用户信息

        userInfo = mysql.get(id);

        // 将userInfo变为映射关系使用hmset保存到Redis中

        redis.hmset(userRedisKey, transferUserInfoToMap(userInfo));

        // 添加过期时间?

        redis.expire(userRedisKey, 3600);

    }?

    return userInfo;?

}

但是需要注意的是哈希类型和关系型数据库有两点不同之处:

哈希类型是稀疏的,而关系型数据库是完全结构化的,例如哈希类型每个键可以有不同的field,而关系型数据库一旦添加新的列,所有行都要为其设置值(即使为NULL),如图2-17所示。

关系型数据库可以做复杂的关系查询,而Redis去模拟关系型复杂查询开发困难,维护成本高。

 

图2-17 关系型数据库稀疏性

开发人员需要将两者的特点搞清楚,才能在适合的场景使用适合的技术。到目前为止,我们已经能够用三种方法缓存用户信息,下面给出三种方案的实现方法和优缺点

分析。

1)原生字符串类型:每个属性一个键。

set user:1:name tom

set user:1:age 23?

set user:1:city beijing

优点:简单直观,每个属性都支持更新操作。

缺点:占用过多的键,内存占用量较大,同时用户信息内聚性比较差,所以此种方案一般不会在生产环境使用。

2)序列化字符串类型:将用户信息序列化后用一个键保存。

set user:1 serialize(userInfo)

优点:简化编程,如果合理的使用序列化可以提高内存的使用效率。

缺点:序列化和反序列化有一定的开销,同时每次更新属性都需要把全部数据取出进行反序列化,更新后再序列化到Redis中。

3)哈希类型:每个用户属性使用一对field-value,但是只用一个键保存。

hmset user:1 name tom?age 23 city beijing

优点:简单直观,如果使用合理可以减少内存空间的使用。

缺点:要控制哈希在ziplist和hashtable两种内部编码的转换,hashtable会消耗更多内存。

相关文章
|
9月前
|
人工智能 OLAP 数据处理
解锁数仓内AI流水线,AnalyticDB Ray基于多模ETL+ML提效开发与运维
AnalyticDB Ray 是AnalyticDB MySQL 推出的全托管Ray服务,基于开源 Ray 的丰富生态,经过多模态处理、具身智能、搜索推荐、金融风控等场景的锤炼,对Ray内核和服务能力进行了全栈增强。
|
8月前
|
SQL 运维 自然语言处理
Dataphin智能化重磅升级!编码难题一扫光,开发运维更高效!
Dataphin重磅推出三大核心智能化能力:智能代码助手提升SQL开发效率;智能运维助手实现移动化任务管理;智能分析通过自然语言生成SQL,助力数据价值释放。未来将持续开放智能ETL、安全助手等能力,助力企业构建高效、稳定的数据资产体系。
638 0
|
5月前
|
NoSQL 算法 Redis
【Docker】(3)学习Docker中 镜像与容器数据卷、映射关系!手把手带你安装 MySql主从同步 和 Redis三主三从集群!并且进行主从切换与扩容操作,还有分析 哈希分区 等知识点!
Union文件系统(UnionFS)是一种**分层、轻量级并且高性能的文件系统**,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem) Union 文件系统是 Docker 镜像的基础。 镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
709 6
|
12月前
|
人工智能 运维 安全
AI大模型运维开发探索第四篇:智能体分阶段演进路线
本文探讨了智能体工程的演进历程,从最初的思维链(智能体1.0)到实例化智能体(智能体2.0),再到结构化智能体(智能体3.0),最终展望了自演进智能体(智能体4.0)。文章详细分析了各阶段遇到的问题及解决策略,如工具调用可靠性、推理能力提升等,并引入了大模型中间件的概念以优化业务平台与工具间的协调。此外,文中还提到了RunnableHub开源项目,为读者提供了实际落地的参考方案。通过不断迭代,智能体逐渐具备更强的适应性和解决问题的能力,展现了未来AI发展的潜力。
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
1212 79
|
8月前
|
敏捷开发 运维 数据可视化
DevOps看板工具中的协作功能:如何打破开发、测试与运维之间的沟通壁垒
在DevOps实践中,看板工具通过可视化任务管理和自动化流程,提升开发与运维团队的协作效率。它支持敏捷开发、持续交付,助力团队高效应对需求变化,实现跨职能协作与流程优化。
|
8月前
|
人工智能 运维 自然语言处理
首个智能体模型实测:产品、开发、运维“全包了”
2025年,AI进入“动手”时代。智谱发布新一代大模型GLM-4.5,全球排名第三、国产第一,专为智能体设计,融合推理、编码与智能体能力,实现自主规划与执行任务。通过8个Demo展示其强大能力,涵盖网页设计、课件制作、小游戏开发等,展现其“带手的脑”特性,推动AI从实验室走向真实场景。
430 0
|
存储 缓存 NoSQL
Redis哈希结构在提升数据检索速度中的实践应用
本文详细介绍了 Redis 哈希结构的特点、常见使用场景以及如何在实际应用中利用哈希结构提升数据检索速度。通过合理使用 Redis 哈希结构,可以显著提高系统的性能和响应速度。在实际开发中,结合具体业务需求,灵活运用 Redis 提供的多种数据结构,构建高效的缓存和数据存储解决方案。希望本文能帮助您更好地理解和应用 Redis 哈希结构,提升数据检索速度。
436 18
|
存储 分布式计算 Hadoop
【产品升级】Dataphin V4.4重磅发布:开发运维提效、指标全生命周期管理、智能元数据生成再升级
Dataphin V4.4版本引入了多项核心升级,包括级联发布、元数据采集扩展、数据源指标上架、自定义属性管理等功能,大幅提升数据处理与资产管理效率。此外,还支持Hadoop集群管理、跨Schema数据读取、实时集成目标端支持Hudi及MaxCompute delta等技术,进一步优化用户体验。
1220 3
【产品升级】Dataphin V4.4重磅发布:开发运维提效、指标全生命周期管理、智能元数据生成再升级