《閑扯Redis九》Redis五種數據類型之Set型



一、前言

Redis 提供了5種數據類型:String(字符串)、Hash(哈希)、List(列表)、Set(集合)、Zset(有序集合),理解每種數據類型的特點對於redis的開發和運維非常重要。

原文解析

Redis五種數據類型

Redis 中的 Set 是我們經常使用到的一種數據類型,根據使用方式的不同,可以應用到很多場景中。

二、底層實現

 集合對象的編碼可以是 intset 或者 hashtable 。

 intset 編碼的集合對象使用整數集合作為底層實現, 集合對象包含的所有元素都被保存在整數集合里面。

 舉個例子, 以下代碼將創建一個如圖 8-12 所示的 intset 編碼集合對象:

redis> SADD numbers 1 3 5
(integer) 3

結構圖 8-12:

Redis五種數據類型

 另一方面, hashtable 編碼的集合對象使用字典作為底層實現, 字典的每個鍵都是一個字符串對象, 每個字符串對象包含了一個集合元素, 而字典的值則全部被設置為 NULL 。

舉個例子, 以下代碼將創建一個如圖 8-13 所示的 hashtable 編碼集合對象:

redis> SADD fruits "apple" "banana" "cherry"
(integer) 3

結構圖 8-13:

Redis五種數據類型

三、編碼轉換

 當集合對象可以同時滿足以下兩個條件時, 對象使用 intset 編碼:

1.集合對象保存的所有元素都是整數值;
2.集合對象保存的元素數量不超過 512 個;

 不能滿足這兩個條件的集合對象需要使用 hashtable 編碼。

注意 : 第二個條件的上限值是可以修改的, 具體請看配置文件中關於 set-max-intset-entries 選項的說明。對於使用 intset 編碼的集合對象來說, 當使用 intset 編碼所需的兩個條件的任意一個不能被滿足時, 對象的編碼轉換操作就會被執行: 原本保存在整數集合中的所有元素都會被轉移並保存到字典里面, 並且對象的編碼也會從 intset 變為 hashtable。

 舉個例子, 以下代碼創建了一個只包含整數元素的集合對象, 該對象的編碼為 intset :

redis> SADD numbers 1 3 5
(integer) 3

redis> OBJECT ENCODING numbers
"intset"

 不過, 只要我們向這個只包含整數元素的集合對象添加一個字符串元素,集合對象的編碼轉移操作就會被執行

redis> SADD numbers "seven"
(integer) 1

redis> OBJECT ENCODING numbers
"hashtable"

 除此之外, 如果我們創建一個包含 512 個整數元素的集合對象, 那么對象的編碼應該會是 intset :

redis> EVAL "for i=1, 512 do redis.call('SADD', KEYS[1], i) end" 1 integers
(nil)

redis> SCARD integers
(integer) 512

redis> OBJECT ENCODING integers
"intset"

 但是, 只要我們再向集合添加一個新的整數元素, 使得這個集合的元素數量變成 513 , 那么對象的編碼轉換操作就會被執行:

redis> SADD integers 10086
(integer) 1

redis> SCARD integers
(integer) 513

redis> OBJECT ENCODING integers
"hashtable"

四、命令實現

 因為集合鍵的值為集合對象, 所以用於集合鍵的所有命令都是針對集合對象來構建的, 以下表格列出了其中一部分集合鍵命令, 以及這些命令在不同編碼的集合對象下的實現方法。

命令 intset 編碼的實現方法 hashtable 編碼的實現方法
SADD 調用 intsetAdd 函數, 將所有新元素添加到整數集合里面。 調用 dictAdd , 以新元素為鍵, NULL 為值, 將鍵值對添加到字典里面。
SCARD 調用 intsetLen 函數, 返回整數集合所包含的元素數量, 這個數量就是集合對象所包含的元素數量。 調用 dictSize 函數, 返回字典所包含的鍵值對數量, 這個數量就是集合對象所包含的元素數量。
SISMEMBER 調用 intsetFind 函數, 在整數集合中查找給定的元素, 如果找到了說明元素存在於集合, 沒找到則說明元素不存在於集合。 調用 dictFind 函數, 在字典的鍵中查找給定的元素, 如果找到了說明元素存在於集合, 沒找到則說明元素不存在於集合。
SMEMBERS 遍歷整個整數集合, 使用 intsetGet 函數返回集合元素。 遍歷整個字典, 使用 dictGetKey 函數返回字典的鍵作為集合元素。
SRANDMEMBER 調用 intsetRandom 函數, 從整數集合中隨機返回一個元素。 調用 dictGetRandomKey 函數, 從字典中隨機返回一個字典鍵。
SPOP 調用 intsetRandom 函數, 從整數集合中隨機取出一個元素, 在將這個隨機元素返回給客戶端之后, 調用 intsetRemove 函數, 將隨機元素從整數集合中刪除掉。 調用 dictGetRandomKey 函數, 從字典中隨機取出一個字典鍵, 在將這個隨機字典鍵的值返回給客戶端之后, 調用dictDelete 函數, 從字典中刪除隨機字典鍵所對應的鍵值對。
SREM 調用 intsetRemove 函數, 從整數集合中刪除所有給定的元素。 調用 dictDelete 函數, 從字典中刪除所有鍵為給定元素的鍵值對。

五、應用場景

1.抽獎

抽獎
    1)用戶參與抽獎:SADD order 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
    2)查看所有參與抽獎的人:SMEMBERS order
    3)重復抽獎每次抽取兩人:SMEMBERS order 2
    4)不重復抽獎,三等獎3人,二等獎2人,一等獎1人
        SPOP order 3
        SPOP order 2
        SPOP order 1

2.點贊、收藏、標簽

點贊、收藏、標簽
    1)點贊的人:SADD like:1 1001 1002 1003 1004 1005
    2)取消點贊:SREM like:1 1002
    3)檢查用戶是否點贊過:
        SISMEMBER like:1 1002
        SISMEMBER like:1 1005
    4)獲取點贊人員列表:SMEMBERS like:1
    5)獲取點贊總人數:SCARD like:1

3.關注模型

redis> SADD wangwu zhangsan lisi zhaoliu haoba
    (integer) 4
redis> SADD zhangsan lisi wangwu sijiu
    (integer) 3
redis> SADD lisi zhaoliu zhangsan qinshi
    (integer) 3
redis> SINTER wangwu zhangsan
    1) "lisi"
redis> SISMEMBER zhangsan lisi
    (integer) 1
redis> SISMEMBER lisi zhangsan
    (integer) 1
redis> SISMEMBER zhaoliu zhangsan
    (integer) 0
redis> SISMEMBER haoba zhangsan
    (integer) 0
redis> SDIFF zhangsan wangwu
    1) "sijiu"
    2) "wangwu"
redis> SDIFF lisi wangwu
    1) "qinshi"

六、要點總結

(1)集合對象的編碼可以是 intset 或者 hashtable 。

(2)intset 編碼的集合對象使用整數集合作為底層實現。

(3)hashtable 編碼的集合對象使用字典作為底層實現。

(4)intset 與 hashtable 編碼之間,符合條件的情況下,可以轉換。

over

Redis五種數據類型


免責聲明!

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



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