Redis5種常用數據類型的使用以及內部編碼


String

字符串類型是redis的最基本類型,首先無論值是什么數據類型,其鍵都是字符串,且其他數據類型的數據結構都是在字符串的基礎上搭建的,相信讀者能夠體會到字符串在redis的地位是有多么的重要。

那么字符串的值可以是什么呢?

  • 簡單的字符串,復雜的字符串如JSON,XML的格式的字符串都是可以的。
  • 數字(整數、浮點數)
  • 二進制如音頻、圖片的

當然值的大小不是無限的,不然的話你買內存的錢就可以買整個宇宙了。redis規定其值最大不能大過512M。

操作String

  • 往redis種插入字符串類型的值

    set key value
    
  • 根據鍵獲取值

    get key
    
  • 查看字符串長度

    strlen key
    
  • 批量設置值

    mset key value [key value]
    
  • 批量取值

    mget key [key]
    

批量操作的命令可有效地提高開發命令,但mget、mset的時間復雜度是O(n),因此一次設置的鍵值對多的話,可能會引起redis服務器的阻塞。

  • 如果字符串類型的值是數字,自增命令(每次加1)

    incr key
    
  • 指定每次加的值

    incrby key amount
    
  • 如果字符串類型的值是數字,自減命令(每次減1)

    decr key 
    
  • 往字符串里面追加字符串 (類似JAVA中StringBuilder的append)

    append key value
    
  • 根據開始索引和結束索引獲取字符串的部分

    getrange key start_index end_index
    
  • 根據索引設定指定位置的值

    setrange key index value
    
  • 設置后,其他命令不能夠修改該鍵值,直到鍵刪除或者時間到了后釋放(redis官方給出了使用setnx實現分步鎖的方式)

    set key value nx ex 10
    
  • 為鍵設置秒級過期時間/毫秒級過期時間

    setex/setpx key 10 value
    

String的內部編碼

字符串類型的內部編碼有三種類型:

  • int 8個字節的長整型
  • embstr 小於等於32字節的字符串
  • raw 大於32字節

redis的底層數據結構類似JAVA中的ArrayList類型,都是有着預分配冗余空間,防止反復的空間擴展降低效率,redis中規定如果當前的字符串大小小於1M時擴容都是當前大小的加倍,而如果字符串的大小大於1M的時候,無論大於多少只會擴容1M,而前面說到redis規定值的大小只有512M。

List

List類型是用來存儲多個有序字符串的,List中的每個元素稱為元素,可以往左push添加元素,也可以往右push元素,當然也可以獲取指定范圍的元素,還可以按照自己的需求獲取List中指定的元素。一個列表中最多可以存儲2^23-1個元素,它底層其實是一個雙向的鏈表,對兩端的性能很高,而通過索引下標操作中間的節點時性能會較差。

List有如下兩個特點:

  • List中的元素都是有序的,因此我們能夠根據索引或者起始位置加終止位置獲取我們想要的值。
  • List中的元素是能夠重復。

操作List

  • 往左插入元素

    lpush key value [value]
    
  • 往右插入元素

    rpush key value [value]
    
  • 往值位置的前面或者后面加入元素

    linsert key BEFORE|AFTER value new_value
    
  • 根據起始索引和終止索引查看范圍的值

    lrange key start_index end_index
    
  • 根據值在列表中的索引查找值

    lindex key index
    
  • 獲取列表的長度

    lren key
    
  • 彈出列表左邊的元素

    lpop key
    
  • 彈出列表右邊的元素

    rpop key
    
  • 刪除指定元素

    lrem key count value
    

  • 裁剪列表

    ltrim key start_index end_index
    
  • 修改特定的值

    lset key index value
    
  • 阻塞式向右彈出

    brpop key
    
  • 阻塞式向左彈出

    blpop key
    

List內部編碼

列表類型的內部編碼有兩種。

  • ziplist:當列表的值元素個數小於list-max-ziplist-entries(默認是512個),且每個元素的值小於64自己時,redis采用ziplist的形式存儲列表,減少了內存的使用。
  • linkedlist:當列表其值不滿足ziplist的條件的時候,redis會采用鏈表的形式存儲值。

但在redis3.2版本之后(筆者采用的是redis6.2.5),當元素大於512個或元素大小超過64個字節,內部編碼已從linkedlist變為quicklist。

quicklist采用了ziplist的優點和linkedlist的優點,也就是每個節點都是一個ziplist節點之間用雙向的指針聯系起來,這樣即使得內存使用的減少滿足了快速的插入和刪除,也減少了空間的冗余。

Set

Set類型也是用來存儲多個元素的,但是集合內的元素是無序的,而且它不允許有重復的元素出現在同一個鍵中,類似JAVA中的Set集合。這些特性促使了用戶在操作集合時沒有辦法通過索引去查找元素,也沒有辦法去獲取一個范圍之內的值。與List一樣,redis規定一個集合類型中最多可以存儲2^23-1個元素,同時集合還支持交集、並集、差集,功能頗多。

操作Set

  • 往集合中插入元素

    sadd key value [value]
    
  • 刪除集合中的元素

    srem key value
    
  • 查詢一個集合中的元素的個數

    scard key
    
  • 判斷一個元素於一個集合中存在與否

    sismember key value
    
  • 隨機在集合中獲取想要個數的元素(默認是一個)

    srandmember key [count]
    
  • 隨機在集合中彈出想要個數的元素(默認是一個)

    spop key [count]
    
  • 查詢一個集合中所有的元素

    smembers key 
    
  • 對兩個集合做交集計算

    sinter first_key second_key
    
  • 對兩個集合做並集計算

    sunion first_key second_key
    
  • 對兩個集合做差集計算

    sdiff first_key second_key
    
  • 將兩個集合交\並\差集的計算結果存入另一個鍵中

    sinterstore store_key first_key second_key
    sunionstore store_key first_key second_key
    sdiffstore store_key first_key second_key
    

Set的內部編碼

  • intset:當集合中的元素都是整數且元素的個數不超過set-max-intset-entries(512)時,redis內部用intset來實現集合,目的還是為了減少內存的使用。
  • hashtable:當集合內部的元素類型、個數不滿足intset的要求的話,redis將用hsahtable來實現集合的內部。就如JAVA中的HashSet一樣其內部使用HashMap來實現的,只不過是多個值對一個鍵,hashtable和其一樣,內部都是用HashMap來實現的,也是多個值對一個鍵。

Hash

Hash可以是哈希,字典,也可以是關聯數組。在redis中,哈希類型指值是一個鍵值對結構,這有點套娃,不知道為什么筆者總感覺其值很像JSON對象。哈希類型中的映射關系叫作field-value,這里的value是指值中field對應的值,可不敢是鍵的值。筆者認為Hash特點適合去存儲對象,當然String類型也可以去存儲對象的信息,但是你說一個人的特征拆成塊,放到大海中,需要的時候去尋找,你就不怕男變女嗎? Hash中鍵可以存儲多個field-value,每個field不能相同,field與value映射,這就很好地把一個對象兜起來了。

操作Hash

  • 插入數據

    hset key field value [field value]
    
  • 根據field取出值

    hget key field
    
  • 批量插入數據

    hmset key field value [key field value] 
    
  • 根據field批量取出數據

    hmget key field [field]
    
  • 根據field刪除數據

    hdel key field [field]
    
  • 查看哈希類型所有的field

    hkeys key
    
  • 查看哈希類型所有的value

    hvals key
    
  • 判斷field是否存在

    hexists key field
    
  • 獲取哈希所有的field-value

    hgetall key
    

Hash內部編碼

  • ziplist: 當哈希類型元素小於hash-max-ziplist-entries(默認512個),且其大小小於hash-max-ziplist-value(62字節)時,redis內部采用ziplist形式對其編碼,目的是為了減少內存的使用,為什么?因為內存很貴啊。
  • hashtable: 當哈希類型元素不滿足ziplist的條件時,redis內部使用hashtable的形式對其編碼。hashtable就像JAVA中的HashSet一樣,底層都是用HashMap實現的,特點是一個鍵對多個值,我想哈希類型的field-value十分像Map<String,Object>,可能其底層是Map<String,Map<String,Object>>,很套娃很喜歡。

Zset

Zset與Set相似,一樣是集合,集合中的元素不能夠相同,但是不同的是有序集合的每一個元素都有自己的分數,所以有序集合可以根據分數來進行排序,這也說明我們能夠以索引/分數的方式獲取到一個或者一個范圍中的值。在實際的開發中,有序集合給我們提供了分數查詢,范圍查詢,事物排行榜的功能。

盡管有序集合中,元素不能夠相同,但是各元素的分數是能夠相同的!拜托!你是你我是我,又不是抄你試卷,為什么分數不能一樣呢?

操作Zset

  • 往有序集合中添加元素

    zadd key score value [score value]
    
  • 刪除有序集合中的元素

    zrem key value
    
  • 計算有序集合中元素的個數

    zcard key
    
  • 計算某個元素的分數

    zscore key value
    
  • 查詢某個元素的排名

    zrank key value
    zrevrank key value//倒序排名
    
  • 獲取指定排名的元素

    zrange key start end
    zrange key start end withscores
    zrevrange key start end
    zrevrange key start end withscores
    

有序集合是按照分數的高低來排名的,所以zrange命令獲取的是一份從低到高的排行榜,zrevrange反之,而后面帶着withscores命令的,在展示排行榜的時候會帶上每一個元素的分數。

  • 為指定元素增加指定分數

    zincrby key value score
    
  • 根據分數的范圍獲取指定范圍的元素

    zrangebyscore key min max  [withscores]
    zrevrangebyscore key max min  [withscores]
    

其中min、max支持開區間,閉區間,而-inf和+inf分別代表無窮小和無窮大。

示例:

  • 有序集合的交\並\差集計算

    zinterstore store_key num_key actual_key [actual_key]
    zunionstore store_key num_key actual_key [actual_key]
    zdiffstore store_key num_key actual_key [actual_key]
    

此計算與集合的計算一致,多了個num_key,其實就是你要計算的鍵的數量,相較於集合來說便是一次可計算多個鍵。

Zset內部編碼

  • ziplist: 當有序集合中的元素個數不超過zset-max-ziplist-entires(512),且每個元素的大小不超過zset-max-ziplist-value時,zset在redis的內部編碼是ziplist,減少內存的使用。
  • skiplist: 當有序集合里的元素不滿足ziplist的條件時,zset在redis的內部編碼是shiplist,俗稱跳躍表。

所謂的跳躍表便是不循環地遍歷每個節點,而是跳躍形式地搜查,如果搜查到的節點比要找的節點要小的話便繼續跳躍搜查,如果要大的話,便轉換到下一層的搜查,直到找到為止,這比ziplist的查找減少了次數,提高了查找的效率。

似乎redis的單線程結構挺重要的,但是由於我現在不想寫,所以等有空的時候吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM