redis数据结构之哈希
几乎所有的编程语言都提供了哈希类型,在不同的语言中又被称为字符表、字典、关联数组、映射等。在redis中,哈希类型是指键值本身又是一个键值对结构,类似value={{field1,value1},{field2, value2}},redis键值对和哈希类型关系如下图所示:
image.png
哈希数据结构基本命令
- 设置值: hset key field value
- 获取值: hget key field
- 删除键: hdel key field
- 判断field是否存在 hexist key field
- 获取所有value: hval key
- 获取所有field: hkeys key
- 获取所有field-value: hgetall user:1
hset user:1 name tom
hget user:1 name
tom
hdel user:1 name
hexists user:1 name
hkeys user:1
hvals user:1
当使用hgetall时,若哈希元素个数比较多,会存在阻塞redis的可能。
哈希类型的内部编码
-
ziplist(压缩列表): 当哈希类型元素个数小于hash-max-ziplist-entries(默认512)并且所有值都小于64字节(hash-max-ziplist-value的默认配置),redis会采用ziplist作为哈希的内部实现,ziplist相比hashtable存储结构更紧凑,它是连续存储,更节省内存。但ziplist随着元素的增多,读写效率会下降。
-
hashtable(哈希表): 当哈希类型不满足使用ziplist的条件时,redis会使用hashtable作为哈希的内部实现,hashtable相比ziplist读写效率更快,时间复杂度为O(1)。
127.0.0.1:6379> hmset key f1 v1 f2 v2
OK
127.0.0.1:6379> object encoding key
"ziplist"
127.0.0.1:6379> hset longkey f3 "my name is tracy i like playing basketball and love wangziyan very much, strive for success we can make it come on !!!! let us make big !!!!!!!!!!!!!! very long word enough greater than 64"
(integer) 1
127.0.0.1:6379> object encoding longkey
"hashtable"
127.0.0.1:6379>
可以看出,当field个数比较少且没有大的value时,内部编码为ziplist, 而当value大小大于64字节时,内部编码会由ziplist变为hashtable。(若field个数大于512内部编码也会由ziplist变为hashtable, 太长了,就不举例了)
哈希类型的使用场景
在关系型数据库中,我们通常使用一个记录来表示一条用户信息,每个字段代表用户的一个属性。
image.png
这其实可以通过哈希类型来缓存用户信息,而且表达的更加直观,操作也更快
image.png
由于哈希类型每个键可以有不同的field,一旦添加新的列,(比如,某些用户是vip,有些不同与普通用户的属性)不必像关系型数据库那样所有的记录都要添加新的列(没有该属性的也要设置为null)。而关系型数据库支持复杂关系查询,哈希类型去模拟这种复杂关系查询,维护成本较高。
image.png提出一个问题
如果让你去缓存用户信息,有哪几种方式?
- 使用原生字符串类型, 每个属性作为一个键
127.0.0.1:6379> set user:1:name t-mac
OK
127.0.0.1:6379> set user:1:age 25
OK
127.0.0.1:6379> set user:1:city hangzhou
OK
这种方式实现起来简单直观,每个属性都可以直接进行更新。但它占用了太多的键,内存消耗大,并且用户信息的内聚性差,因此,很少使用这种方法在生成环境。
- 使用序列化字符串类型,每条记录序列化后用一个键保存, set user:1 serialized(userInfo)。 合理使用序列化可以提高内存的使用率,但序列化和反序列化有一定的开销。
- 使用哈希类型,每个用户的属性使用field-value,一个用户对应一个键。
hmset user:1 name t-mac age 23 city hanzhoug
哈希类型实现简单直接,读写效率快,但需要控制哈希在ziplist和hashtable内部编码的转换。
总的来说,需要根据具体的业务场景来选择合适的方法!