Redis中Hash類型總結(jié)(數(shù)據(jù)結(jié)構(gòu)、操作與常用場景)

哈希

幾乎所有的編程語言都提供了哈希(hash)類型,它們的叫法可能是哈希、字典、關(guān)聯(lián)數(shù)組在Redis中,哈希類型是指鍵值本身又是一個(gè)鍵值對結(jié)構(gòu),形如value={{field1,value1},...{fieldN,valueN}}/

命令

1.hset key field value 設(shè)置值
hset user:1 name tom

2.hget key field    獲取值,如果鍵或field不存在,會(huì)返回nil:

3.hdel key field [field ...] 刪除field,會(huì)刪除一個(gè)或多個(gè)field,返回結(jié)果為成功刪除field的個(gè)數(shù)

4.hlen key 計(jì)算field個(gè)數(shù)

5.hmget key field [field...] hmset key field value [field value..]批量設(shè)置或獲取field-value
    hmset和hmget分別是批量設(shè)置和獲取field-value,hmset需要的參數(shù)是key 和多對field-value,hmget需要的參數(shù)是key和多個(gè)field。

6.hexists key field  判斷field是否存在

7.hkeys key 獲取所有field

8.hvals key  獲取所有value

在使用hgetall時(shí),如果哈希元素個(gè)數(shù)比較多,會(huì)存在阻塞Redis的可能。如果開發(fā)人員只需要獲取部分field,可以使用hmget,如果一定要獲取全部 field-value,可以使用hscan命令,該命令會(huì)漸進(jìn)式遍歷哈希類型,

9.  hincrby key field 
    hincrbyfloat key field
    incrby和incrbyfloat命令一樣,但是它們的作用域是filed

10.hstrlen key field  計(jì)算value的字符串長度(需要Redis3.2以上

內(nèi)部編碼

哈希類型的內(nèi)部編碼有兩種:

·ziplist(壓縮列表):當(dāng)哈希類型元素個(gè)數(shù)小于hash-max-ziplist-entries 配置(默認(rèn)512個(gè))、同時(shí)所有值都小于hash-max-ziplist-value配置(默認(rèn)64 字節(jié))時(shí),Redis會(huì)使用ziplist作為哈希的內(nèi)部實(shí)現(xiàn),ziplist使用更加緊湊的結(jié)構(gòu)實(shí)現(xiàn)多個(gè)元素的連續(xù)存儲(chǔ),所以在節(jié)省內(nèi)存方面比hashtable更加優(yōu)秀。

·hashtable(哈希表):當(dāng)哈希類型無法滿足ziplist的條件時(shí),Redis會(huì)使用hashtable作為哈希的內(nèi)部實(shí)現(xiàn),因?yàn)榇藭r(shí)ziplist的讀寫效率會(huì)下降,而 hashtable的讀寫時(shí)間復(fù)雜度為O(1)

數(shù)據(jù)結(jié)構(gòu)

提供兩種結(jié)構(gòu)來存儲(chǔ),一種是hashtable、另一種是前面講的ziplist,數(shù)據(jù)量小的時(shí)候用ziplist. 在redis中,哈希表分為三層,分別是,源碼地址【dict.h】

dictEntry

管理一個(gè)key-value,同時(shí)保留同一個(gè)桶中相鄰元素的指針,用來維護(hù)哈希桶的內(nèi)部鏈;

typedef struct dictEntry {
void *key;
union { //因?yàn)関alue有多種類型,所以value用了union來存儲(chǔ)
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;//下一個(gè)節(jié)點(diǎn)的地址,用來處理碰撞,所有分配到同一索引的元素通過next指針
鏈接起來形成鏈表key和v都可以保存多種類型的數(shù)據(jù)
} dictEntry;

dictht

實(shí)現(xiàn)一個(gè)hash表會(huì)使用一個(gè)buckets存放dictEntry的地址,一般情況下通過hash(key)%len得到的值就是buckets的索引,這個(gè)值決定了我們要將此dictEntry節(jié)點(diǎn)放入buckets的哪個(gè)索引里,這個(gè)buckets實(shí)際上就是我們說的hash表。dict.h的dictht結(jié)構(gòu)中table存放的就是buckets的地址.

typedef struct dictht {
dictEntry **table;//buckets的地址
unsigned long size;//buckets的大小,總保持為 2^n
unsigned long sizemask;//掩碼,用來計(jì)算hash值對應(yīng)的buckets索引
unsigned long used;//當(dāng)前dictht有多少個(gè)dictEntry節(jié)點(diǎn)
} dictht;

dict

dictht實(shí)際上就是hash表的核心,但是只有一個(gè)dictht還不夠,比如rehash、遍歷hash等操作,所以redis定義了一個(gè)叫dict的結(jié)構(gòu)以支持字典的各種操作,當(dāng)dictht需要擴(kuò)容/縮容時(shí),用來管理dictht的遷移,以下是它的數(shù)據(jù)結(jié)構(gòu),源碼在

typedef struct dict {
dictType *type;//dictType里存放的是一堆工具函數(shù)的函數(shù)指針,
void *privdata;//保存type中的某些函數(shù)需要作為參數(shù)的數(shù)據(jù)
dictht ht[2];//兩個(gè)dictht,ht[0]平時(shí)用,ht[1] rehash時(shí)用
long rehashidx; //當(dāng)前rehash到buckets的哪個(gè)索引,-1時(shí)表示非rehash狀態(tài)
int iterators; //安全迭代器的計(jì)數(shù)。
} dict;

比如我們要講一個(gè)數(shù)據(jù)存儲(chǔ)到hash表中,那么會(huì)先通過murmur計(jì)算key對應(yīng)的hashcode,然后根據(jù)hashcode取模得到bucket的位置,再插入到鏈表中/
整體結(jié)構(gòu)如圖所示:


使用場景

存儲(chǔ)關(guān)系型數(shù)據(jù)表的數(shù)據(jù)

用戶的屬性作為表的列,每條用戶信息作為行。如果將其用哈希類型存儲(chǔ)相比于使用字符串序列化緩存用戶信息,哈希類型變得更加直觀,并且在更新操作上會(huì)更加便捷??梢詫⒚總€(gè)用戶的id定義為鍵后綴,多對fieldvalue對應(yīng)每個(gè)用戶的屬性。哈希類型是稀疏的,而關(guān)系型數(shù)據(jù)庫是完全結(jié)構(gòu)化的,例如哈希類型每個(gè)鍵可以有不同的field,而關(guān)系型數(shù)據(jù)庫一旦添加新的列,所有行都要為其設(shè)置值(即使為NULL),如圖2-17所示。

·關(guān)系型數(shù)據(jù)庫可以做復(fù)雜的關(guān)系查詢,而Redis去模擬關(guān)系型復(fù)雜查詢開發(fā)困難,維護(hù)成本高。

哈希類型:每個(gè)用戶屬性使用一對field-value,但是只用一個(gè)鍵保存。

hmset user:1 name tomage 23 city beijing

優(yōu)點(diǎn):簡單直觀,如果使用合理可以減少內(nèi)存空間的使用。

缺點(diǎn):要控制哈希在ziplist和hashtable兩種內(nèi)部編碼的轉(zhuǎn)換,hashtable會(huì)消耗更多內(nèi)存。

待續(xù)。。。

來自《Redis運(yùn)維與開發(fā)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • String 字符串 存儲(chǔ)類型 可以用來存儲(chǔ)字符串、整數(shù)、浮點(diǎn)數(shù)。 操作命令 設(shè)置多個(gè)值(批量操作,原子性) 設(shè)置...
    WEIJAVA閱讀 1,405評論 0 4
  • 轉(zhuǎn)載:可能是目前最詳細(xì)的Redis內(nèi)存模型及應(yīng)用解讀 Redis是目前最火爆的內(nèi)存數(shù)據(jù)庫之一,通過在內(nèi)存中讀寫數(shù)據(jù)...
    jwnba24閱讀 694評論 0 4
  • 前言 Redis是目前最火爆的內(nèi)存數(shù)據(jù)庫之一,通過在內(nèi)存中讀寫數(shù)據(jù),大大提高了讀寫速度,可以說Redis是實(shí)現(xiàn)網(wǎng)站...
    小陳阿飛閱讀 895評論 0 1
  • 簡單工廠模式:一種創(chuàng)建型設(shè)計(jì)模式 應(yīng)用場景:通過一個(gè)對象(工廠),創(chuàng)建很多其他對象(產(chǎn)品)。 實(shí)現(xiàn)方式:所有產(chǎn)品類...
    JeremyYv閱讀 339評論 0 4
  • 2020年2月6日,星期四,天氣多云。明天就是正月十四了,是孩子整七歲的生日。好多天都沒有逛街了,不知道外面的蛋糕...
    大智若愚_dca5閱讀 354評論 0 3

友情鏈接更多精彩內(nèi)容