Redis数据结构之哈希表
这里的哈希表说的是value的类型是哈希表
一.相关命令
1.hset key field value
一次可以设置多个
返回值是设置成功的个数
注意,哈希表中的键值对,键是唯一的而值可以重复
所以有下面的结果:
key中原来已经有了f1,所以再使用hset时,返回值是0,表示没有设置新的字段,但是根据hget的结果可以知道,f1的value已经修改了
2.hget key field获取指定的字段的值
这里的字段指的是field,而不是key
时间复杂度:O(1)
3.hexists key field 判官是否有指定的字段
这里的字段指的是field
一次只能判断一个字段
返回值:1表示存在,0表示不存在
时间复杂度:O(1)
4.hdel key field
一次可以删除多个
返回值是成功删除掉的个数
时间复杂度:O(1)
5.hkeys key获取hash中的所有列表
时间复杂度:O(N),N表示key中field的个数,所以当field很少时,就可以看成O(1)
与keys一样有一定的风险,如果field很多,就可能造成其他命令无法及时接收,导致请求偏向mySql,造成mySql崩溃
6.hvals获取hash中所有的值
时间复杂度:O(N)
7.hgetall key 获取hash中所有的字段以及值
时间复杂度:O(N),N表示字段的个数
8.hmget key field [field]一次获取多个字段的值
9.hlen key 获取hash中所有字段的个数
10.hsetnx 在字段不存在的情况下才设置
注意,不存在hsetex
11.hincrby key field increment
返回值是增加后的结果
12.hincrbyfloat key field increment
可以对整数进行加浮点数的操作,也可以对浮点数进行加整数的操作
二.内部编码
redis中hash表的内部编码有两种:ziplist和hashtable
ziplist:压缩列表。
我们常说的rar、zip、gzip、7z……都是一些常见的压缩算法。
压缩的本质:针对数据进行重新编码。不同的数据有不同的特点。结合这些特点,进行精妙的设计,重新编码后就能缩小体积。
例如:abbcccdee,重新编码为1a2b3c1d2e
事实上,上述压缩算法都是精妙设计的,ziplist也同理,内部的数据结构也是精心设计的,节省内存空间。
但是ziplist进行压缩会有代价:读取速度慢。如果元素个数少,则慢的不明显,多了则雪上加霜。
而hashtable的读写时间复杂度是O(1)。
所以只有当hash表中字段个数较少并且每个字段的值也很短时才会使用ziplist,如果元素个数多或者某些字段的值很长就会使用hashtable
三.使用场景
当作缓存,存储结构化数据
前面说过,String也可以作为缓存使用,但是针对于存储结构化数据,使用哈希表类型会更合适
如下是一张关系型数据表保存用户信息:
将它映射到redis中存储,其中value是hash类型,如下:
这里的user1和user2就是键,后面的哈希表就是值。
但是要是使用string字符串存储,就需要用到json这样的数据格式。
就比如某个场景下只需要获取其中的一个field或者修改其中的一个field,那就得把整个json格式的数据全部读取出来,然后解析成对象,再去操作field。操作完毕后再将对象转化成json格式字符串再重新存储。这样真的很麻烦。但要是使用hash来表示userinfo,就可以使用field表示对象的每一个属性,获取时也可以单个field获取,这样的话,读取field更高效。
但是,虽然读取field更高效,却付出了空间的代价!!!因为要控制hash在ziplist和hashtable这两种存储方式的转换中,可能造成内存的大量消耗
哈希类型和关系型数据库的区别
1.哈希类型是稀疏的,而关系型数据库是完全结构化的。就是说哈希类型的每个键可以有不同的value,比如其中一个键设置了地址信息,而另一个键就可以不设置。但要是关系型数据库,一旦添加了新的列,就必须设置值,要么就设置成NULL
缓存方式对比
截至目前,我们已经能够使用三种方式来作为缓存,下面给出三种方式的优缺点
1.原生字符串类型
set user:1:name John
set user:1:age 23
set user:1:address Beijing
优点:实现简单,针对个别属性的变更也很灵活
缺点:占用过多的键,内存占用量较大,同时用户信息再redis中比较分散,缺少内聚性,所以这种方案基本上没有实用性,是低内聚的表现。但是程序设计助球队是高内聚低耦合(高内聚就是把所有相关联的东西放在一起;耦合指的是两个代码/模块之间的关联关系,关联关系越大,相互的影响就越大,耦合度就越高)
2.序列化字符串类型——例如JSON格式的字符串
set user:1 经过序列化后的用户对象字符串
优点:针对总是以整体作为操作的信息比较合适编程成也比较简单,同时。如果序列化方案选择合适,内存使用的效率也很高
缺点:本身序列化和反序列化需要一定的开销,同时如果总是操作个别属性则不是很灵活
3.哈希类型
hmset user:1 name John age 23 address Beijing
优点:简单直观灵活。尤其是针对信息的局部变更和获取
缺点