Redis之Set和Zset使用及說明
Set 集合
集合類型也是保存多個字符串類型的元素的,但和列表類型不同的是,集合中 1)元素之間是無序 的 2)元素不允許重復(fù),如下圖。
一個集合中最多可以存儲 2^32-1個元素。
Redis 除了支持 集合內(nèi)的增刪查改操作,同時還支持多個集合取交集、并集、差集,合理地使用好集合類型,能在實 際開發(fā)中解決很多問題。

普通命令
SADD
將一個或者多個元素添加到 set 中。注意,重復(fù)的元素?zé)o法添加到 set 中。
語法:
SADD key member [member ...]
返回值:本次添加成功的元素個數(shù)。
示例:

SMEMBERS
獲取一個 set 中的所有元素,注意,元素間的順序是無序的。
語法:
SMEMBERS key
返回值:所有元素的列表。
示例:

SISMEMBER
判斷一個元素在不在 set 中。
語法:
SISMEMBER key member
返回值:1 表示元素在 set 中。0 表示元素不在 set 中或者 key 不存在。
示例:

SCARD
獲取一個 set 的基數(shù)(cardinality),即 set 中的元素個數(shù)。
語法:
SCARD key
返回值:set 內(nèi)的元素個數(shù)。
示例:

SPOP
從 set 中刪除并返回一個或者多個元素。注意,由于 set 內(nèi)的元素是無序的,所以取出哪個元素實際是 未定義行為,即可以看作隨機的。
語法:
SPOP key [count]
count:刪除的個數(shù),不寫默認(rèn)是1
返回值:取出的元素。
示例:

srandmember
隨機獲取值
語法:
srandmember key [count]
示例:

SMOVE
將一個元素從源 set 取出并放入目標(biāo) set 中。
語法:
SMOVE source destination member
返回值:1 表示移動成功,0 表示失敗。
示例:

SREM
將指定的元素從 set 中刪除。
語法:
SREM key member [member ...]
返回值:本次操作刪除的元素個數(shù)。
示例:

集合間操作
交集(inter)、并集(union)、差集(diff)的概念如下圖

SINTER
獲取給定 set 的交集中的元素。
語法:
SINTER key [key ...]
返回值:交集的元素。
示例:

SINTERSTORE
獲取給定 set 的交集中的元素并保存到目標(biāo) set 中。
語法:
SINTERSTORE destination key [key ...]
返回值:交集的元素個數(shù)。
示例:

SUNION
獲取給定 set 的并集中的元素。
語法:
SUNION key [key ...]
返回值:并集的元素。
示例:


SUNIONSTORE
獲取給定 set 的并集中的元素并保存到目標(biāo) set 中。
語法:
SUNIONSTORE destination key [key ...]
返回值:并集的元素個數(shù)。
示例:

SDIFF
獲取給定 set 的差集中的元素。
語法:
SDIFF key [key ...]
返回值:差集的元素。
示例:

SDIFFSTORE
獲取給定 set 的差集中的元素并保存到目標(biāo) set 中。
語法:
SDIFFSTORE destination key [key ...]
返回值:差集的元素個數(shù)。
示例:


命令小結(jié)

內(nèi)部編碼
集合類型的內(nèi)部編碼有兩種:
- intset(整數(shù)集合):當(dāng)集合中的元素都是整數(shù)并且元素的個數(shù)小于 set-max-intset-entries 配置 (默認(rèn) 512 個)時,Redis 會選用 intset 來作為集合的內(nèi)部實現(xiàn),從而減少內(nèi)存的使用。
- hashtable(哈希表):當(dāng)集合類型無法滿足 intset 的條件時,Redis 會使用 hashtable 作為集合 的內(nèi)部實現(xiàn)。
使用場景
集合類型比較典型的使用場景是標(biāo)簽(tag)。例如 A 用戶對娛樂、體育板塊比較感興趣,B 用戶 對歷史、新聞比較感興趣,這些興趣點可以被抽象為標(biāo)簽。有了這些數(shù)據(jù)就可以得到喜歡同一個標(biāo)簽 的人,以及用戶的共同喜好的標(biāo)簽,這些數(shù)據(jù)對于增強用戶體驗和用戶黏度都非常有幫助。 例如一個 電子商務(wù)網(wǎng)站會對不同標(biāo)簽的用戶做不同的產(chǎn)品推薦。
Zset 有序集合
有序集合相對于字符串、列表、哈希、集合來說會有一些陌生。它保留了集合不能有重復(fù)成員的 特點,但與集合不同的是,有序集合中的每個元素都有一個唯一的浮點類型的分?jǐn)?shù)(score)與之關(guān) 聯(lián),這使得有序集合中的元素是可以維護有序性的,但這個有序不是用下標(biāo)作為排序依據(jù)而是用這個 分?jǐn)?shù)。
如下圖所示,該有序集合顯示了三國中的武將的武力。

有序集合提供了獲取指定分?jǐn)?shù)和元素范圍查找、計算成員排名等功能,合理地利用有序集合,可 以幫助我們在實際開發(fā)中解決很多問題。
有序集合中的元素是不能重復(fù)的,但分?jǐn)?shù)允許重復(fù)。類比于一次考試之后,每個人一定有一 個唯一的分?jǐn)?shù),但分?jǐn)?shù)允許相同。
列表、集合、有序集合三者的異同點:

普通命令
ZADD
添加或者更新指定的元素以及關(guān)聯(lián)的分?jǐn)?shù)到 zset 中,分?jǐn)?shù)應(yīng)該符合 double 類型,+inf/-inf 作為正負 極限也是合法的。
ZADD 的相關(guān)選項:
- XX:僅僅用于更新已經(jīng)存在的元素,不會添加新元素。
- NX:僅用于添加新元素,不會更新已經(jīng)存在的元素。
- CH:默認(rèn)情況下,ZADD 返回的是本次添加的元素個數(shù),但指定這個選項之后,就會還包含本次更 新的元素的個數(shù)。
- INCR:此時命令類似 ZINCRBY 的效果,將元素的分?jǐn)?shù)加上指定的分?jǐn)?shù)。此時只能指定一個元素和 分?jǐn)?shù)。
- LT:less than,只更新已經(jīng)存在的元素,如果新的分?jǐn)?shù)比當(dāng)前分?jǐn)?shù)小,那么更新就成功
- GT:greater than,只更新已經(jīng)存在的元素,如果新的分?jǐn)?shù)比當(dāng)前分?jǐn)?shù)大,那么更新就成功
語法:
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]
返回值:本次添加成功的元素個數(shù)。
示例:

當(dāng)前查詢結(jié)果是有序的(升序)

修改趙云的分?jǐn)?shù)

帶nx選項,如果不存在就更新。返回值是新增元素的個數(shù)

帶xx選項,如果存在就修改值,返回值是0,因為沒有新增元素,所以是0.

不加ch,默認(rèn)返回新增的元素個數(shù),帶上ch選項,就要再加上修改的元素的個數(shù)。

ZCARD
獲取一個 zset 的基數(shù)(cardinality),即 zset 中的元素個數(shù)。
語法:
ZCARD key
返回值:zset 內(nèi)的元素個數(shù)。
示例:

ZCOUNT
返回分?jǐn)?shù)在 min 和 max 之間的元素個數(shù),默認(rèn)情況下,min 和 max 都是包含的,可以通過 ( 排除。
語法:
ZCOUNT key min max
返回值:滿足條件的元素列表個數(shù)。
示例:

默認(rèn)是包含邊界的

不包含邊界的話要加上 (
ZRANGE
返回指定區(qū)間里的元素,分?jǐn)?shù)按照升序。帶上 WITHSCORES 可以把分?jǐn)?shù)也返回。
語法:
ZRANGE key start stop [WITHSCORES]
此處的 [start, stop] 為下標(biāo)構(gòu)成的區(qū)間. 從 0 開始, 支持負數(shù).
返回值:區(qū)間內(nèi)的元素列表。
示例:

ZREVRANGE
返回指定區(qū)間里的元素,分?jǐn)?shù)按照降序。帶上 WITHSCORES 可以把分?jǐn)?shù)也返回。
備注:這個命令可能在 6.2.0 之后廢棄,并且功能合并到 ZRANGE 中。
語法:
ZREVRANGE key start stop [WITHSCORES]
返回值:區(qū)間內(nèi)的元素列表。
示例:

ZRANGEBYSCORE
返回分?jǐn)?shù)在 min 和 max 之間的元素,默認(rèn)情況下,min 和 max 都是包含的,可以通過 ( 排除。
備注:這個命令可能在 6.2.0 之后廢棄,并且功能合并到 ZRANGE 中。
語法:
ZRANGEBYSCORE key min max [WITHSCORES]
返回值:區(qū)間內(nèi)的元素列表。
示例:

ZPOPMAX
刪除并返回分?jǐn)?shù)最高的 count 個元素。
語法:
ZPOPMAX key [count]
返回值:分?jǐn)?shù)和元素列表。
示例:

如果存在多個元素,他們的分?jǐn)?shù)相同,同時為最大值,zpopmax刪的時候,仍然只刪除其中一個元素!

BZPOPMAX
ZPOPMAX 的阻塞版本。
語法:
BZPOPMAX key [key ...] timeout
返回值:元素列表。
示例:

剛開始key里沒有數(shù)據(jù),就會阻塞,插入元素后,就會立即返回
ZPOPMIN
刪除并返回分?jǐn)?shù)最低的 count 個元素。
語法:
ZPOPMIN key [count]
返回值:分?jǐn)?shù)和元素列表。
示例:

BZPOPMIN
ZPOPMIN 的阻塞版本。
語法:
BZPOPMIN key [key ...] timeout
返回值:元素列表。
ZRANK
返回指定元素的排名,升序。
語法:
ZRANK key member
返回值:排名。
示例:

ZREVRANK
返回指定元素的排名,降序。
語法:
ZREVRANK key member
返回值:排名。
ZSCORE
返回指定元素的分?jǐn)?shù)。
語法:
ZSCORE key member
返回值:分?jǐn)?shù)。
示例:

ZREM
刪除指定的元素。
語法:
ZREM key member [member ...]
返回值:本次操作刪除的元素個數(shù)。
示例:

ZREMRANGEBYRANK
按照排序,升序刪除指定范圍的元素,左閉右閉。
語法:
ZREMRANGEBYRANK key start stop
返回值:本次操作刪除的元素個數(shù)。
示例:

ZREMRANGEBYSCORE
按照分?jǐn)?shù)刪除指定范圍的元素,左閉右閉,可以用 ( 排除邊界值。
語法:
ZREMRANGEBYSCORE key min max
返回值:本次操作刪除的元素個數(shù)。
示例:

ZINCRBY
為指定的元素的關(guān)聯(lián)分?jǐn)?shù)添加指定的分?jǐn)?shù)值。
語法:
ZINCRBY key increment member
返回值:增加后元素的分?jǐn)?shù)。
示例:

集合間操作
有序集合的交集操作

ZINTERSTORE
求出給定有序集合中元素的交集并保存進目標(biāo)有序集合中,在合并過程中以元素為單位進行合并,元 素對應(yīng)的分?jǐn)?shù)按照不同的聚合方式和權(quán)重得到新的分?jǐn)?shù)。
語法:
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>]
返回值:目標(biāo)集合中的元素個數(shù)
示例1:


示例2:


weights后面跟的2和3 就是權(quán)重。2是key的,3是key2的,把key里面的元素的分?jǐn)?shù)都乘2,就從10,20,30變成20,40,60.把key2里面的元素的分?jǐn)?shù)都乘3,就變成45,75,105。
返回結(jié)果中,交集的zhangsan就是20+45=65
示例3:

aggregate就是交集分?jǐn)?shù)的聚合方式
有序集合的并集操作

ZUNIONSTORE
求出給定有序集合中元素的并集并保存進目標(biāo)有序集合中,在合并過程中以元素為單位進行合并,元 素對應(yīng)的分?jǐn)?shù)按照不同的聚合方式和權(quán)重得到新的分?jǐn)?shù)。
語法:
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>]
返回值:目標(biāo)集合中的元素個數(shù)
示例1:

示例2:

命令小結(jié)

內(nèi)部編碼
有序集合類型的內(nèi)部編碼有兩種:
- ziplist(壓縮列表):當(dāng)有序集合的元素個數(shù)小于 zset-max-ziplist-entries 配置(默認(rèn) 128 個), 同時每個元素的值都小于 zset-max-ziplist-value 配置(默認(rèn) 64 字節(jié))時,Redis 會用 ziplist 來作 為有序集合的內(nèi)部實現(xiàn),ziplist 可以有效減少內(nèi)存的使用。
- skiplist(跳表):當(dāng) ziplist 條件不滿足時,有序集合會使用 skiplist 作為內(nèi)部實現(xiàn),因為此時 ziplist 的操作效率會下降。
使用場景
有序集合比較典型的使用場景就是排行榜系統(tǒng)。例如常見的網(wǎng)站上的熱榜信息,榜單的維度可能 是多方面的:按照時間、按照閱讀量、按照點贊量。
漸進式遍歷
Redis 使用 scan 命令進行漸進式遍歷鍵,進而解決直接使用 keys 獲取鍵時可能出現(xiàn)的阻塞問 題。每次 scan 命令的時間復(fù)雜度是 O(1),但是要完整地完成所有鍵的遍歷,需要執(zhí)行多次 scan。
整 個過程如下圖所示:

- 首次 scan 從 0 開始.
- 當(dāng) scan 返回的下次位置為 0 時, 遍歷結(jié)束.
SCAN
以漸進式的方式進行鍵的遍歷。
語法:
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
COUNt:后面接數(shù)字,表示建議返回幾個值,不一定就是指定的個數(shù),但也不會差太多。
返回值:下一次 scan 的游標(biāo)(cursor)以及本次得到的鍵。
示例:


第一次遍歷,返回的cursor是15,所以下一次遍歷要從15開始。第二次返回的cursor是0,說明遍歷已經(jīng)結(jié)束了。
示例2:

第一次遍歷時,count后面是3,結(jié)果返回了4個,說明返回的個數(shù)不一定就是你指定的個數(shù),只是建議返回幾個。
除了 scan 以外,Redis 面向哈希類型、集合類型、有序集合類型分別提供了 hscan、sscan、zscan 命 令,它們的用法和 scan 基本類似
漸進性遍歷 scan 雖然解決了阻塞的問題,但如果在遍歷期間鍵有所變化(增加、修改、刪 除),可能導(dǎo)致遍歷時鍵的重復(fù)遍歷或者遺漏,這點務(wù)必在實際開發(fā)中考慮。
數(shù)據(jù)庫管理
Redis 提供了幾個面向 Redis 數(shù)據(jù)庫的操作,分別是 dbsize、select、flushdb、flushall 命令。
切換數(shù)據(jù)庫
select dbIndex
許多關(guān)系型數(shù)據(jù)庫,例如 MySQL 支持在一個實例下有多個數(shù)據(jù)庫存在的,但是與關(guān)系型數(shù)據(jù)庫用 字符來區(qū)分不同數(shù)據(jù)庫名不同,Redis 只是用數(shù)字作為多個數(shù)據(jù)庫的實現(xiàn)。Redis 默認(rèn)配置中是有 16 個數(shù)據(jù)庫。select 0 操作會切換到第一個數(shù)據(jù)庫,select 15 會切換到最后一個數(shù)據(jù)庫。0 號數(shù)據(jù)庫和 15 號數(shù)據(jù)庫保存的數(shù)據(jù)是完全不沖突的(如下圖所示),即各種有各自的鍵值對。默認(rèn)情況下,我 們處于數(shù)據(jù)庫 0。

Redis 中雖然支持多數(shù)據(jù)庫,但隨著版本的升級,其實不是特別建議使用多數(shù)據(jù)庫特性。如 果真的需要完全隔離的兩套鍵值對,更好的做法是維護多個 Redis 實例,而不是在一個 Redis 實例中維護多數(shù)據(jù)庫。這是因為本身 Redis 并沒有為多數(shù)據(jù)庫提供太多的特性,其次 無論是否有多個數(shù)據(jù)庫,Redis 都是使用單線程模型,所以彼此之間還是需要排隊等待命令 的執(zhí)行。同時多數(shù)據(jù)庫還會讓開發(fā)、調(diào)試和運維工作變得復(fù)雜。所以實踐中,始終使用數(shù)據(jù) 庫 0 其實是一個很好的選擇。
示例:

清除數(shù)據(jù)庫
flushdb / flushall 命令用于清除數(shù)據(jù)庫,區(qū)別在于 flushdb 只清除當(dāng)前數(shù)據(jù)庫,flushall 會清楚所有數(shù) 據(jù)庫。
永遠不要在線上環(huán)境執(zhí)行清除數(shù)據(jù)的操作,除非你想體驗一把 “從刪庫到跑路” 的操作。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Redis數(shù)據(jù)刪除與淘汰策略從原理到實戰(zhàn)指南
本文講解了Redis的數(shù)據(jù)刪除與淘汰策略,從基礎(chǔ)概念鋪墊到策略細節(jié)拆解,再到底層原理和實戰(zhàn)配置,重點介紹了三種刪除策略(惰性刪除、定期刪除、主動刪除)和六種常用淘汰策略(allkeys-lru、volatile-lru、allkeys-lfu、volatile-lfu等),感興趣的朋友跟隨小編一起看看吧2026-04-04

