Redis中hash数据类型的相关命令、编码方式和应用场景

hash数据类型的相关命令:

命令描述时间复杂度
hset key field value设置给定key的field的值O(1)
hget key field获取给定key的field的值O(1)
hdel key f1 f2 ..删除给定key中的一个或多个fieldO(N)
hlen key计算给定key中field的个数O(1)
hgetall key获取给定key中所有的field-valueO(N)
hmget key f1 f2 ...批量获取给定key中的field-valueO(N)
hmset key f1 v1 f2 v2 ...批量设置给定key中的field-valueO(N)
hexists key field判断给定key中的field是否存在O(1)
hkeys key获取给定key中所有的fieldO(N)
hvals key获取给定key中所有的valueO(N)
hsetnx key field value设置给定key的field的值,仅当field不存在时才能设置成功O(1)
hincrby key field n给给定key中的field-value增加整数nO(1)
hincrbyfloat key field n给给定key中的field-value增加浮点数nO(1)
hstrlen key field计算给定key中field对应的value的字符串长度O(1)
hscan变量redis的hash渐进式遍历,每敲一次命令遍历一小部分相当于O(1)

可以看出如果是涉及某一个数据操作的命令时间复杂度一般都为O(1),如果涉及全部或者一部分数据进行操作的命令的时间复杂度为O(N),这里的N可能有三种情况:

  1. Redis中存储数据的规模
  2. 当前命令中key的规模
  3. 当前命令key对应的value里面元素的规模

对于时间复杂度O(N)的操作,都存在一定的风险,这些操作可能会占据Redis服务器太长时间导致其他命令阻塞,类似于keys *的影响。

hscan的这种操作属于化整为零的思想。Java中ConcurrentHashMap线程安全的哈希表在扩容的时候也是化整为零的方式进行的

hash数据类型的实际编码方式:

哈希的内部编码有两种:

  • ziplist(压缩列表):当哈希类型元素个数小于 hash-max-ziplist-entries 配置(默认 512 个)、 同时所有值都小于 hash-max-ziplist-value 配置(默认 64 字节)时,Redis 会使用 ziplist 作为哈希的内部实现,ziplist 使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面 hashtable 更加优秀。
  • hashtable(哈希表):当哈希类型无法满足 ziplist 的条件时,Redis 会使用 hashtable 作为哈希 的内部实现,因为此时 ziplist 的读写效率会下降,而 hashtable 的读写时间复杂度为 O(1)。

常见的压缩手段有让rar、zip、gzip、7z等等,压缩的本质是对数据进行重新编码,比如:“abbcccddddeeeee”可以压缩成“a1b2c3d4e5”;或者“abcd000000000000000000000abcd”可以压缩成“abcd0[24]abcd”。ziplist也是同样的到了,对于普通的hash表可能会浪费一些空间(hash首先是一个数组,有些位置上有元素,有些位置没有元素),ziplist经过了精心的设计节省了一些空间但也导致查询速度变慢付出了一定的代价。

  • 哈希表中的元素比较少会使用ziplist,元素个数据表多会使用hashtable来作为实际变法方式
  • 每个value的长度都比较短时使用ziplist,如果value长度太长会使用hashtable进行编码

hash数据类型的应用场景:

作为缓存:

存储结构化的数据时,使用hash类型会更合适一些,所谓结构化的数据就是类似于数据库中表这样的结构。

为什么选择hash类型存储结构化的数据?以上图中的user为例我们来对比一下常见的几种形式:

  1. 使用原生字符串:对uid、name等属性使用字符串类型,每个属性一个键(内聚低);
  2. 将结构化的数据序列化为字符串类型,例如 JSON 格式,对属性的操作不够灵活;
  3. 使用hash类型来存储,简单直观,操作方便,只是需要控制哈希在 ziplist 和 hashtable 两种内部编码的转换,可能会造成内存的较大消耗。

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

  • 哈希类型是稀疏的,而关系型数据库是完全结构化的,例如哈希类型每个键可以有不同的 field,而关系型数据库⼀旦添加新的列,所有行都要为其设置值,即使为 null。
  • 关系数据库可以做复杂的关系查询,而Redis 去模拟关系型复杂查询,例如联表查询、聚合查询等基本不可能,维护成本高。

关于高内聚、低耦合:

这里举写例子描述一下,并非专业概括:

内聚:是指把有关联的数据放在一起,最好能放在指定的位置。比如,衣服应该都放在衣柜里,如果衣服放的比较乱,房间哪哪都是,那么再找某一件衣服的时候就需要遍历整个房间,这就低内聚。如果都整齐的放在衣柜里,就可以快速的在衣柜里找到,这就是高内聚。

耦合:模块/代码之间关联关系,关联关系越大,越容易相互影响,认为是耦合大。比如,夫妻之间的关联关系就比较大,如果老婆生病了,老公就要请假照顾,模块之间容易受到影响。再比如,如果是一个朋友圈点赞之交的朋友生病了,因为关联关系并不大,所以对我并没有什么影响,就不用请假。

  • 25
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值