Redis學習筆記—遍歷鍵

全量遍歷鍵

keys pattern

查看所有的key、“J”開頭的key、“T”或者“J”開頭的key

127.0.0.1:6379> keys *
1) "Tom"
2) "Jerry"
3) "hello"
4) "Java"
127.0.0.1:6379> keys J*
1) "Jerry"
2) "Java"
127.0.0.1:6379> keys [T,J]*
1) "Tom"
2) "Jerry"
3) "Java"

如果redis數據量數據量有大量鍵, keys命令有可能造成redis阻塞,如果不清楚有多少鍵的情況下避免在生產環境使用keys命令

漸進式遍歷

Redis從2.8版本後,提供了一個新的命令scan,它能有效的解決keys命令存在的問題。和keys命令執行時會遍歷所有鍵不同,scan採用漸進式遍歷的方式來解決keys命令可能帶來的阻塞問題,每次scan命令的時間複雜度是O(1),但是要真正實現keys的功能,需要執行多次scan。

Redis存儲鍵值對實際使用的是hashtable的數據結構,那麼每次執行scan,可以想象成只掃描一個字典中的一部分鍵,直到將字典中的所有鍵遍歷完畢

scan cursor [MATCH pattern] [COUNT count]
  • cursor是必需參數,實際上cursor是一個遊標,第一次遍歷從0開始,每次scan遍歷完都會返回當前遊標的值,直到遊標值爲0,表示遍歷結束
  • match pattern是可選參數,它的作用的是做模式的匹配,這點和keys的模式匹配很像
  • count number是可選參數,它的作用是表明每次要遍歷的鍵個數,默認值是10,此參數可以適當增大

把剛剛6666端口實例清空(flushdb命令),然後添加英文字母26個key用作測試

127.0.0.1:6666> flushdb
OK
127.0.0.1:6666> keys *
(empty list or set)
127.0.0.1:6666> mset a a b b c c d d e e f f g g h h i i j j k k l l m m n n o o p p q q r r s s t t u u v v w w x x y y z z 
OK

第一次執行scan0,返回結果分爲兩個部分:第一個部分1就是下次scan需要的cursor,第二個部分是10個鍵:

127.0.0.1:6666> scan 0
1) "1"
2)  1) "u"
    2) "w"
    3) "g"
    4) "a"
    5) "b"
    6) "m"
    7) "z"
    8) "q"
    9) "i"
   10) "y"

使用新的cursor=“1”,scan 1 返回下一次的cursor=“29”是個鍵

127.0.0.1:6666> scan 1
1) "29"
2)  1) "n"
    2) "e"
    3) "t"
    4) "f"
    5) "c"
    6) "s"
    7) "h"
    8) "x"
    9) "o"
   10) "j"

使用得到的新的cursor=“29”,scan 29 返回結果cursor變成0,說明所有的鍵都已經遍歷過了

127.0.0.1:6666> scan 29
1) "0"
2) 1) "p"
   2) "v"
   3) "r"
   4) "l"
   5) "k"
   6) "d"

除了scan以外,Redis提供了面向哈希類型、集合類型、有序集合的掃描遍歷命令,解決諸如hgetall、smembers、zrange可能產生的阻塞問題,對應的命令分別是hscan、sscan、zscan,它們的用法和scan基本類似,下面以sscan爲例子進行說明,當前集合有兩種類型的元素,例如分別以old:user和new:user開頭,先需要將old:user開頭的元素全部刪除,可以參考如下僞代碼:

String key = "myset";
//定義 pattern
String pattern = "old:user*";
//遊標每次從 0 開始
String cursor = "0";
while (true) {
    //獲取掃描結果
    ScanResult scanResult = redis.sscan(key, cursor, pattern);
    List elements = scanResult.getResult();
    if (elements != null && elements.size() > 0) {
    //批量刪除
        redis.srem(key, elements);
    }
    //獲取新的遊標
    cursor = scanResult.getStringCursor();
    //如果遊標爲 0 表示遍歷結束
    if ("0".equals(cursor)) {
        break;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章