前言
⼏乎所有的主流编程语⾔都提供了哈希(hash)类型,它们的叫法可能是哈希、字典、关联数组、映射。在 Redis 中,哈希类型是指 value 本⾝⼜是⼀个键值对结构,形如 key = "key",value = { { field1, value1 }, ..., {fieldN, valueN } },是嵌套的哈希表
哈希类型中的映射关系通常称为 field-value,⽤于区分 Redis 整体的键值对(key-value), 注意这⾥的 value 是指 field 对应的值,不是键(key)对应的值
命令
以下 H 系列的命令必须要保证 key 对应的 value 得是 hash 类型的
HSET 设置哈希中的 field - value
语法
HSET key field value [field value ...]
时间复杂度:插⼊⼀组 field 为 O(1), 插⼊ N 组 field 为 O(N)
返回值:添加的字段的个数。
HGET 获取 hash 中指定字段的值
语法
HGET key field
时间复杂度:O(1)
返回值:字段对应的值或者 nil。
HEXISTS 判断 hash 中是否有指定的字段
语法
HEXISTS key field
时间复杂度:O(1)
返回值:1 表⽰存在,0 表⽰不存在。
HDEL 删除 hash 中指定的字段
语法
HDEL key field [field ...]
时间复杂度:删除⼀个元素为O(1).删除 N 个元素为 O(N).
返回值:本次操作删除的字段个数。
HKEYS 获取 hash 中的所有字段
语法
HKEYS key
时间复杂度:O(N)
N 为 field 的个数.返回值:字段列表。
这个操作,先根据 key 找到对应的 hash ,然后再遍历这个 hash 表,由于会遍历并打印出 hash 表中的全部内容,而我们并不知道 hash 表中有多少内容,所以这个操作是有一定风险的,如果 hash 表中的数据较多,就会导致该命令执行很长的一段时间,而 redis 是单线程的程序,就会造成阻塞,并且后面的 HVALS ,HGETALL 都存在这样的风险
HVALS 获取 hash 中的所有的值
语法
HVALS key
时间复杂度:O(N), N 为 field 的个数
返回值:所有的 value 值。
标题一HGETALL 获取 hash 中的所有字段 field 以及对应的值 value
语法
HGETALL key
时间复杂度:O(N), N 为 field 的个数
返回值:字段和对应的值。
HMGET ⼀次获取 hash 中多个字段的值
语法
HMGET key field [field ...]
时间复杂度:只查询⼀个元素为 O(1), 查询多个元素为 O(N), N 为查询元素个数.
返回值:字段对应的值或者 nil
HLEN 获取 hash 中的所有字段的个数
语法
HLEN key
时间复杂度:O(1),redis 使用变量保存了 hash 表中的字段个数
返回值:字段个数
HSETNX 在字段不存在的情况下,设置 hash 中的字段和值
可以理解为 “创建” 只有不存在才能创建,存在就创建失败
语法
HSETNX key field value
时间复杂度:O(1)
返回值:1 表⽰设置成功,0 表⽰失败。
HINCRBY 将 hash 中字段对应的数值添加指定的值
语法
HINCRBY key field increment
时间复杂度:O(1)
返回值:该字段变化之后的值
HINCRBYFLOAT 将 hash 中字段对应的数值添加指定的浮点值
语法
HINCRBYFLOAT key field increment
时间复杂度:O(1)
返回值:该字段变化之后的值
内部编码
哈希的内部编码有两种:
• ziplist(压缩列表):当哈希类型元素个数⼩于 hash-max-ziplist-entries 配置(默认 512 个)、 同时所有值都⼩于 hash-max-ziplist-value 配置(默认 64 字节)时,Redis 会使⽤ ziplist 作为哈 希的内部实现,ziplist 使⽤更加紧凑的结构实现多个元素的连续存储,所以在节省内存⽅⾯⽐ hashtable 更加优秀。
• hashtable(哈希表):当哈希类型⽆法满⾜ ziplist 的条件时,Redis 会使⽤ hashtable 作为哈希 的内部实现,因为此时 ziplist 的读写效率会下降,⽽ hashtable 的读写时间复杂度为 O(1)。
简单总结:当哈希表中的键值对个数较少,每个键值对值 value 的长度较短时,哈希的内部编码采用的就是 ziplist(压缩列表) ,而较少和较短的边界值就要看具体的配置,使用 ziplist (压缩列表)相比于 hashtable 要节省很大的空间,但相对的读取数据的速度较慢,尤其当数据较多或者 value 值较长时会很明显,所以当数据较多或 value 值较长时会将内部编码从 ziplist(压缩列表)改为 hashtable(哈希表)
使用场景
通常采用 hash 类型来保存对象的相关属性信息,比如关系型数据库中保存了以下的用户信息
可以将其保存到 redis 中,value 的类型是 hash
相⽐于使⽤ JSON 格式的字符串缓存⽤户信息,哈希类型变得更加直观,并且在更新操作上变得更灵活。可以将每个⽤户的 id 定义为键后缀,多对 field-value 对应⽤户的各个属性
要注意哈希类型和关系型数据库有两点不同之处
• 哈希类型是稀疏的,⽽关系型数据库是完全结构化的,例如哈希类型每个键可以有不同的 field,⽽关系型数据库⼀旦添加新的列,所有⾏都要为其设置值,即使为 null
• 关系数据库可以做复杂的关系查询,⽽ Redis 去模拟关系型复杂查询,例如联表查询、聚合查询等基本不可能,维护成本⾼。