Redis 的 hash 的基本命令暂时先不多说, 我们直接步入正文 在 Redis 的 hash 结构中, 存在这样一种现象
- 127.0.0.1:6379> hset user:001 name john age 25 sex man
- (integer) 3
- 127.0.0.1:6379> hgetall user:001
- 1) "name"
- 2) "john"
- 3) "age"
- 4) "25"
- 5) "sex"
- 6) "man"
我们先给 user:001 分别设置了 name,age,sex 属性, 然后通过 hgetall 获取所有属性, 这一切看起来还比较正常 但是接下来
- 127.0.0.1:6379> hset user:002 name john age 25 sex man extra xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- (integer) 4
- 127.0.0.1:6379> hgetall user:002
- 1) "name"
- 2) "john"
- 3) "extra"
- 4) "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- 5) "sex"
- 6) "man"
- 7) "age"
- 8) "25"
我们给 user:002 多设置了一个 extra 属性, 并且设置的值比较大, 然后用 hgetall 获取所有属性的时候发现返回的顺序不是按照我们设置的时候的属性的顺序了, 这是为什么呢?
其实主要原因是: hash 数据结构底层实现为一个字典(dict), 也是 redisDb 用来存储 k-v 的数据结构, 当数据量比较小, 或者单个元素比较小的时候, 底层用 ziplist 存储, 数据大小和元素数量阈值可以通过如下参数设置
hash-max-ziplist-entries 512 //ziplist 元素个数超过 512, 将改为 hashtable 编码 hash-max-ziplist-value 64 // 单个元素大小超过 64byte 时, 将改为 hashtable 编码 对于上面的例子, 主要是因为单个元素大小超过了 64byte, 所以改为了 hashtable 编码, 导致了 hgetall 获取属性的时候和设置的顺序不一样
压缩表的结构
其实很多同学也有一个疑问, hash 和 string 类型到底有啥本质的区别? 其实我们从源码可以看出来, 对于 string 类型来说, string 类型是基于 RedisDb 的, 如果 string 的数量不断的变多, 就会导致 dictht 部分不断的 rehash
而对于 hash 类型的来说, hash 不存在 dictht 不断 rehash 的问题
但是其实也是各有利弊, 比如 hash 就没法对某个 key 设置过期时间, 而且 Redis 中有一个很大的忌讳, 就是不要让某个 key 过大, 容易阻塞, 所以个人还是更推荐 string 的方式
来源: http://stor.51cto.com/art/202109/683902.htm