全量遍歷鍵
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;
}
}