天天看點

Redis學習——資料結構下

4、集合(集合(set)類型也是用來儲存多個的字元串元素,但和清單類型不一樣的是,集合中不允許有重複元素,并且集合中的元素是無序的,不能通過索引下标擷取元素。)

1、指令

.集合内操作

1、添加元素 sadd key element [element ...]傳回結果為添加成功的元素個數。

2、删除元素 srem key element [element ...]傳回結果為成功删除元素個數。

3、計算元素個數 scard key

(scard的時間複雜度為O(1),它不會周遊集合所有元素,而是直接用Redis内部的變量)

4、判斷元素是否在集合中 sismember key element 如果給定元素element在集合内傳回1,反之傳回0

5、随機從集合傳回指定個數元素 srandmember key [count] [count]是可選參數,如果不寫預設為1

6、從集合随機彈出元素 spop key (spop操作可以從集合中随機彈出一個元素,Redis從3.2版本開始,spop也支援[count]參數)

7、擷取所有元素 smembers key

(smembers和lrange、hgetall都屬于比較重的指令,如果元素過多存在阻塞Redis的可能性,這時候可以使用sscan來完成)

.集合間操作

1、求多個集合的交集 sinter key [key ...]

2、求多個集合的并集 suinon key [key ...]

3、求多個集合的差集 sdiff key [key ...]

4、将交集、并集、差集的結果儲存 sinterstore destination key [key ...]

suionstore destination key [key ...]

sdiffstore destination key [key ...]

   (集合間的運算在元素較多的情況下會比較耗時,是以Redis提供了上面三個指令(原指令+store)将集合間交集、并集、差集的結果儲存在

destination key中,例如下面操作将user:1:follow和user:2:follow兩個集合的交集結果儲存在user:1_2:inter中,user:1_2:inter本身也是集合類

sinterstore user:1_2:inter user:1:follow user:2:follow

    )

2、内部編碼

·intset(整數集合):當集合中的元素都是整數且元素個數小于set-max-intset-entries配置(預設512個)時,Redis會選用intset來作為集合的内部實作,進而減少記憶體的使用。

·hashtable(哈希表):當集合類型無法滿足intset的條件時,Redis會使用hashtable作為集合的内部實作。

3、使用場景(集合類型比較典型的使用場景是标簽(tag)。)

(例如一個使用者可能對娛樂、體育比較感興趣,另一個使用者可能對曆史、新聞比較感興趣,這些興趣

                         點就是标簽。有了這些資料就可以得到喜歡同一個标簽的人,以及使用者的共

                         同喜好的标簽,這些資料對于使用者體驗以及增強使用者黏度比較重要。例如一

                         個電子商務的網站會對不同标簽的使用者做不同類型的推薦,比如對數位産品

                         比較感興趣的人,在各個頁面或者通過郵件的形式給他們推薦最新的數位産

                         品,通常會為網站帶來更多的利益)

集合類型的應用場景通常為以下幾種

·sadd=Tagging(标簽)

·spop/srandmember=Random item(生成随機數,比如抽獎)

·sadd+sinter=Social Graph(社交需求)

5、有序集合

( 有序集合相對于哈希、清單、集合來說會有一點點陌生,但既然叫有序集合,那麼它和集合必然有着聯系,它保留了集合不能有重複成員的特性,但不同的是,有序集合中的元素可以排序。但是它和清單使用索引下标作為排序依據不同的是,它給每個元素設定一個分數(score)作為排序的依據。有序集合中的元素不能重複,但是score可以重複,就和一個班裡的同學學号不能重複,但是考試成績可以相同。)

1、指令

·集合内

1、添加成員 zadd key score member [score member ...] 傳回結果代表成功添加成員的個數。

·Redis3.2為zadd指令添加了nx、xx、ch、incr四個選項:

·nx:member必須不存在,才可以設定成功,用于添加。

·xx:member必須存在,才可以設定成功,用于更新。

·ch:傳回此次操作後,有序集合元素和分數發生變化的個數

·incr:對score做增加,相當于後面介紹的zincrby。

·有序集合相比集合提供了排序字段,但是也産生了代價,zadd的時間

複雜度為O(log(n)),sadd的時間複雜度為O(1)。

2、計算成員個數 zcard key

3、計算某個成員的分數 zscore key member

4、計算成員的排名

zrank key member 是從分數從低到高傳回排名,zrevrank反之

5、删除成員 zrem key member [member ...] 傳回結果為成功删除的個數。

6、增加成員的分數 zincrby key increment member

zincrby user:ranking 9 tom(tom增加了9分)

7、傳回指定排名範圍的成員

zrange key start end [withscores]

zrevrange key start end [withscores]

(有序集合是按照分值排名的,zrange是從低到高傳回,zrevrange反之。)

8、傳回指定分數範圍的成員

其中zrangebyscore按照分數從低到高傳回,zrevrangebyscore反之

9、傳回指定分數範圍成員個數

zcount key min max

zcount user:ranking 200 221 :傳回200到221分的成員的個數

10、删除指定排名内的升序元素 

zremrangebyrank key start end :删除第start到第end名的成員

11、删除指定分數範圍的成員  zremrangebyscore key min max

zremrangebyscore user:ranking (250 +inf :将250分以上的成員全部删除

·集合間的操作

1、交集 zinterstore destination numkeys key [key ...] [weights weight [weight ...]][aggregate sum|min|max]

這個指令參數較多,下面分别進行說明:

·destination:交集計算結果儲存到這個鍵。

·numkeys:需要做交集計算鍵的個數。

·key[key...]:需要做交集計算的鍵。

·weights weight[weight...]:每個鍵的權重,在做交集計算時,每個鍵中

的每個member會将自己分數乘以這個權重,每個鍵的權重預設是1。

·aggregate sum|min|max:計算成員交集後,分值可以按照sum(和)、min(最小值)、max(最大值)做彙總,預設值是sum。

2、并集 zunionstore destination numkeys key [key ...] [weights weight [weight ...]][aggregate sum|min|max]

(該指令的所有參數和zinterstore是一緻的,隻不過是做并集計算)

2、内部編碼

·ziplist(壓縮清單):當有序集合的元素個數小于zset-max-ziplist-entries配置(預設128個),同時每個元素的值都小于zset-max-ziplist-value配

置(預設64位元組)時,Redis會用ziplist來作為有序集合的内部實作,ziplist可以有效減少記憶體的使用。

·skiplist(跳躍表):當ziplist條件不滿足時,有序集合會使用skiplist作為内部實作,因為此時ziplist的讀寫效率會下降。

3、使用場景

有序集合比較典型的使用場景就是排行榜系統。例如視訊網站需要對用

戶上傳的視訊做排行榜,榜單的次元可能是多個方面的:按照時間、按照播

放數量、按照獲得的贊數。本節使用贊數這個次元,記錄每天使用者上傳視訊

的排行榜。

6、鍵管理

1、單個鍵管理

針對單個鍵的指令,前面幾節已經介紹過一部分了,例如type、del、object、exists、expire等,下面将介紹剩餘的幾個重要指令。

1、鍵重命名 rename key newkey (如果newKey已經存在,值也會被覆寫)

(為了防止被強行rename,Redis提供了renamenx指令,確定隻有newKey

不存在時候才被覆寫,例如下面操作renamenx時,newkey=python已經存在,

傳回結果是0代表沒有完成重命名,是以鍵java和python的值沒變)

  在使用重命名指令時,有兩點需要注意:

·由于重命名鍵期間會執行del指令删除舊的鍵,如果鍵對應的值比較大,會存在阻塞Redis的可能性,這點不要忽視。

·如果rename和renamenx中的key和newkey如果是相同的,在Redis3.2和之前版本傳回結果略有不同。

2、随機傳回一個鍵 randomkey

3、鍵過期

除了expire、ttl指令以外,Redis還提供了expireat、pexpire、pexpireat、pttl、persist等一系列指令,下面分别進行說明:

·expire key seconds:鍵在seconds秒後過期。

·expireat key timestamp:鍵在秒級時間戳timestamp後過期。

ttl指令和pttl都可以查詢鍵的剩餘過期時間,但是pttl精度更高可以達到毫秒級别,有3種傳回值:

·大于等于0的整數:鍵剩餘的過期時間(ttl是秒,pttl是毫秒)。

·-1:鍵沒有設定過期時間。

·-2:鍵不存在。

·pexpire key milliseconds:鍵在milliseconds毫秒後過期。

·pexpireat key milliseconds-timestamp鍵在毫秒級時間戳timestamp後過期。

在使用Redis相關過期指令時,需要注意以下幾點。

1)如果expire key的鍵不存在,傳回結果為0

2)如果過期時間為負值,鍵會立即被删除,猶如使用del指令一樣

3)persist指令可以将鍵的過期時間清除

4)對于字元串類型鍵,執行set指令會去掉過期時間,這個問題很容易在開發中被忽視。

5)Redis不支援二級資料結構(例如哈希、清單)内部元素的過期功能,例如不能對清單類型的一個元素做過期時間設定。

6)setex指令作為set+expire的組合,不但是原子執行,同時減少了一次網絡通訊的時間

4、遷移鍵

遷移鍵功能非常重要,因為有時候我們隻想把部分資料由一個Redis遷移到另一個Redis(例如從生産環境遷移到測試環境),Redis發展曆程中提

供了move、dump+restore、migrate三組遷移鍵的方法,它們的實作方式以及使用的場景不太相同,下面分别介紹

(1)move: move key db

move指令用于在Redis内部進行資料遷移,Redis内部可以有多個資料庫,彼此在資料上是互相隔離的,move key db就

是把指定的鍵從源資料庫移動到目标資料庫中,多資料庫功能不建議在生産環境使用,是以這個指令讀者知道即可。

(2)dump+restore

dump key

restore key ttl value

dump+restore可以實作在不同的Redis執行個體之間進行資料遷移的功能,整個遷移的過程分為兩步:

1)在源Redis上,dump指令會将鍵值序列化,格式采用的是RDB格式。

2)在目标Redis上,restore指令将上面序列化的值進行複原,其中ttl參數代表過期時間,如果ttl=0代表沒有過期時間。

有關dump+restore有兩點需要注意:

第一,整個遷移過程并非原子性的,而是通過用戶端分步完成的。

第二,遷移過程是開啟了兩個用戶端連接配接,是以dump的結果不是在源Redis和目标Redis之間進行傳輸

(3)migrate

migrate host port key|"" destination-db timeout [copy] [replace] [keys key [key

migrate指令也是用于在Redis執行個體間進行資料遷移的,實際上migrate指令就是将dump、restore、del三個指令進行組合,進而簡化了操作流程。

migrate指令具有原子性,而且從Redis3.0.6版本以後已經支援遷移多個鍵的

功能,有效地提高了遷移效率,migrate在10.4節水準擴容中起到重要作用。

2、周遊鍵(Redis提供了兩個指令周遊所有的鍵,分别是keys和scan)

1.全量周遊鍵 keys pattern (pattern使用的是glob風格的通配符)

·*代表比對任意字元。

·代表比對一個字元。

·[]代表比對部分字元,例如[1,3]代表比對1,3,[1-10]代表比對1到10的任意數字。

·\x用來做轉義,例如要比對星号、問号需要進行轉義

   如果Redis包含了大量的鍵,執行keys指令很可能會造成Redis阻塞,是以一般建議不要在生

   産環境下使用keys指令。但有時候确實有周遊鍵的需求該怎麼辦,可以在以下三種情況使用:

·在一個不對外提供服務的Redis從節點上執行,這樣不會阻塞到用戶端的請求,但是會影響到主從複制。

·如果确認鍵值總數确實比較少,可以執行該指令。

·使用下面要介紹的scan指令漸進式的周遊所有鍵,可以有效防止阻塞。

2.漸進式周遊:scan cursor [match pattern] [count number]

Redis從2.8版本後,提供了一個新的指令scan,它能有效的解決keys指令存在的問題。和keys指令執行時會周遊所有鍵不同,scan采用漸進式周遊

的方式來解決keys指令可能帶來的阻塞問題,每次scan指令的時間複雜度是O(1),但是要真正實作keys的功能,需要執行多次scan。

scan cursor [match pattern] [count number]各參數含義:

·cursor是必需參數,實際上cursor是一個遊标,第一次周遊從0開始,每次scan周遊完都會傳回目前遊标的值,直到遊标值為0,表示周遊結束。

·match pattern是可選參數,它的作用的是做模式的比對,這點和keys的模式比對很像。

·count number是可選參數,它的作用是表明每次要周遊的鍵個數,預設值是10,此參數可以适當增大。

  除了scan以外,Redis提供了面向哈希類型、集合類型、有序集合的掃

  描周遊指令,解決諸如hgetall、smembers、zrange可能産生的阻塞問題,對

  應的指令分别是hscan、sscan、zscan,它們的用法和scan基本類似。

  )

  **漸進式周遊可以有效的解決keys指令可能産生的阻塞問題,但是scan并

    非完美無瑕,如果在scan的過程中如果有鍵的變化(增加、删除、修改),

    那麼周遊效果可能會碰到如下問題:新增的鍵可能沒有周遊到,周遊出了重

    複的鍵等情況,也就是說scan并不能保證完整的周遊出來所有的鍵,這些是我們在開發時需要考慮的。

7、資料庫管理(Redis提供了幾個面向Redis資料庫的操作,它們分别是dbsize、select、flushdb/flushall指令)

1.切換資料庫(Redis是用數字作為多個資料庫的實作。Redis預設配置中是有16個資料庫)

select dbIndex

2.flushdb/flushall

flushdb/flushall指令用于清除資料庫,兩者的差別的是flushdb隻清除目前資料庫,flushall會清除所有資料庫。

flushdb/flushall指令可以非常友善的清理資料,但是也帶來兩個問題:

·flushdb/flushall指令會将所有資料清除,一旦誤操作後果不堪設想。

·如果目前資料庫鍵值數量比較多,flushdb/flushall存在阻塞Redis的可能性。

參考資料:《Redis開發與運維》

轉載于:https://www.cnblogs.com/jnba/p/10811916.html