redis的hash数据类型 是一个键值对集合 也就是数据结构中的集合数据结构,元素除同处一个集合内并无关联性! 它是一个 string 类型的filed value映射表 ,redis本身是 key value类型的数据库 ,hash相当于在value中又嵌套了一层, 基于字典 或 压缩列表实现 ,默认是 基于压缩列表结构 ,因为能够节省空间, 当然我们也可以自己去转换为字典结构!
一,hash表的存储策略
字典又称为符号表.关联数组或者映射,也是一种用于保存键值对的抽象数据结构.字典中的每个建都是独一无二的,程序可以在字典中根据键值查找与之关联的值,或者通过键来更新值,删除等! 当哈希表使用字典编码时, 程序将哈希表的键(key)保存为字典的键, 将哈希表的值(value)保存为字典的值。哈希表所使用的字典的键和值都是字符串对象。
当使用 REDIS_ENCODING_ZIPLIST 编码哈希表时, 程序通过将键和值一同推入压缩列表, 从而形成保存哈希表所需的键-值对结构;新添加的 key-value 对会被添加到压缩列表的表尾。当进行查找/删除或更新操作时,程序先定位到键的位置,然后再通过对键的位置来定位值的位置。
创建空白哈希表时, 程序默认使用 REDIS_ENCODING_ZIPLIST 编码, 当以下任何一个条件被满足时, 程序将编码从 REDIS_ENCODING_ZIPLIST 切换为 REDIS_ENCODING_HT :
这句话是什么意思呢?现在我们来实验一下 redis在什么情况下 会将自动切换 ziplist
第一种情况 key值过长时
第二种情况 filed value 过长时
第三种情况 数据条数过长时
插入五百条记录
仍然是 zillist类型
当我又插入了几条 超过了 512时 redis自动切换成了 hashtable策略
综合以上实验 ,可以得出 redis的 key的长度 不会影响其策略 filed value 数量 这三个元素 皆可影响hsah表的存储策略!
二,hash表的实现
Redis 的 Hash 类型键使用以下两种数据结构作为底层实现:
字典;
压缩列表;
因为压缩列表比字典更节省内存, 所以程序在创建新 Hash 键时, 默认使用压缩列表作为底层实现, 当有需要时, 程序才会将底层实现从压缩列表转换到字典。
/*
* 字典
*
* 每个字典使用两个哈希表,用于实现渐进式 rehash
*/
typedef struct dict {
// 特定于类型的处理函数
dictType *type;
// 类型处理函数的私有数据
void *privdata;
// 哈希表(2 个)
dictht ht[2];
// 记录 rehash 进度的标志,值为 -1 表示 rehash 未进行
int rehashidx;
// 当前正在运作的安全迭代器数量
int iterators;
} dict;
这是字典的源码 ,这里有一个hash表非常重要的概念,重新散列
字典在创建之初,默认是创建了两个ht 也就是我们的hash表,我们用0和1待表;
当我们新增 修改删除时,触发随机散列机制;表0的存储空间不够,表1基于0的大小扩充,
将表0中的数据移动至表1;
二,hash类型的应用场景
购物车
购物车三要素: 用户ID为key,商品ID为field,商品数量为Value 刚好与hash相对应
用户对象存储
hash类型的(key, field, value)的结构与对象的(对象id, 属性, 值)的结构相似,也可以用来存储对象。
string + json也是存储对象的一种方式,那么存储对象时,到底用string + json还是用hash呢?
两种存储方式的对比如下表所示。