Redis鍵指令用於管理redis的鍵。本文就來為大家介紹redis中兩個遍歷redis所有鍵的方法--KEYS pattern和SCAN cursor,希望對大家有一定的幫助。
當我們需要遍歷Redis所有key或指定模式的key時,首先想到的是KEYS指令:
KEYS pattern
官網對於KEYS指令有一個提示: KEYS 的速度非常快,例如,Redis在一個有1百萬個key的資料庫裡面執行一次查詢需要的時間是40毫秒。但在一個大的資料庫中使用它仍然可能造成效能問題,如果你需要從一個資料集中查找特定的 KEYS, 你最好還是用 Redis 的集合結構 SETS 來代替。
KEYS指令使用很簡單。
redis> MSET one 1 two 2 three 3 four 4 OK redis> KEYS *o* 1) "four" 2) "one" 3) "two" redis> KEYS t?? 1) "two" redis> KEYS * 1) "four" 2) "three" 3) "one" 4) "two" redis>
但由於KEYS命令一次返回所有匹配的key,所以,當redis中的key非常多時,對於內存的消耗和redis伺服器都是一個隱患,
對於Redis 2.8以上版本為我們提供了一個更好的遍歷key的命令SCAN 該命令的基本格式:
SCAN cursor [MATCH pattern] [COUNT count]
SCAN 每次執行都只會返回少量元素,所以可以用於生產環境,而不會出現像是KEYS 或SMEMBERS 指令帶來的可能會阻塞伺服器的問題。
SCAN指令是一個基於遊標的迭代器。這表示指令每次被呼叫都需要使用上一次這個呼叫傳回的遊標作為該次呼叫的遊標參數,以此來延續先前的迭代過程
當SCAN指令的遊標參數(即cursor)被設定為0 時, 伺服器將開始一次新的迭代, 而當伺服器向使用者傳回值為0 的遊標時, 表示迭代已結束。
簡單的迭代示範:
redis 127.0.0.1:6379> scan 0 1) "17" 2) 1) "key:12" 2) "key:8" 3) "key:4" 4) "key:14" 5) "key:16" 6) "key:17" 7) "key:15" 8) "key:10" 9) "key:3" 10) "key:7" 11) "key:1" redis 127.0.0.1:6379> scan 17 1) "0" 2) 1) "key:5" 2) "key:18" 3) "key:0" 4) "key:2" 5) "key:19" 6) "key:13" 7) "key:6" 8) "key:9" 9) "key:11"
在上面這個範例中, 第一次迭代使用 0 作為遊標, 表示開始一次新的迭代。第二次迭代使用的是第一次迭代時傳回的遊標 17 ,作為新的迭代參數 。
顯而易見,SCAN指令的傳回值是一個包含兩個元素的數組, 第一個數組元素是用來進行下一個迭代的新遊標, 而第二個數組元素則又是一個數組,這個數組中包含了所有被迭代的元素。
注意:傳回的遊標不一定是遞增的,可能後一次回傳的遊標比前一次的小。
在第二次呼叫 SCAN 指令時, 指令傳回了遊標 0 , 這表示迭代已經結束, 整個資料集已經被完整遍歷過了。
full iteration :以 0 作為遊標開始一次新的迭代, 一直呼叫 SCAN 指令, 直到指令回傳遊標 0 , 我們稱這個過程為一次完整遍歷。
SCAN增量式迭代命令並不保證每次執行都返回某個給定數量的元素,甚至可能會返回零個元素, 但只要命令返回的遊標不是0 , 應用程式就不應該將迭代視作結束。
不過命令返回的元素數量總是符合一定規則的, 對於一個大數據集來說,增量式迭代命令每次最多可能會返回數十個元素;而對於一個足夠小的數據集來說,可能會一次迭代返回所有的key
COUNT選項
對於增量式迭代命令不保證每次迭代所返回的元素數量,我們可以使用COUNT選項, 對命令的行為進行一定程度上的調整。 COUNT 選項的作用是讓使用者告知迭代命令, 在每次迭代中應該從資料集傳回多少元素。使用COUNT 選項對於對增量式迭代指令相當於一種提示, 大多數情況下這種提示都比較有效的控制了傳回值的數量。
注意:COUNT選項並不能嚴格控制回傳的key數量,只能說是一個大致的約束。並非每次迭代都要使用相同的 COUNT 值,使用者可以在每次迭代中按自己的需求隨意改變 COUNT 值, 只要記得將上次迭代傳回的遊標用到下次迭代裡面就可以了。
MATCH 選項
類似於KEYS 指令,增量式迭代指令透過給定MATCH 參數的方式實作了透過提供一個glob 風格的模式參數, 讓指令只回傳和給定模式相符的元素。
MATCH 選項對元素的模式匹配工作是在命令從資料集中取出元素後和向客戶端返回元素前的這段時間內進行的, 所以如果被迭代的資料集中只有少量元素和模式相匹配, 那麼迭代命令或許會在多次執行中都不返回任何元素。
以下是這種情況的一個例子:
redis 127.0.0.1:6379> scan 0 MATCH *11* 1) "288" 2) 1) "key:911" redis 127.0.0.1:6379> scan 288 MATCH *11* 1) "224" 2) (empty list or set) redis 127.0.0.1:6379> scan 224 MATCH *11* 1) "80" 2) (empty list or set) redis 127.0.0.1:6379> scan 80 MATCH *11* 1) "176" 2) (empty list or set) redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000 1) "0" 2) 1) "key:611" 2) "key:711" 3) "key:118" 4) "key:117" 5) "key:311" 6) "key:112" 7) "key:111" 8) "key:110" 9) "key:113" 10) "key:211" 11) "key:411" 12) "key:115" 13) "key:116" 14) "key:114" 15) "key:119" 16) "key:811" 17) "key:511" 18) "key:11" redis 127.0.0.1:6379>
可以看出,以上的大部分迭代都不回傳任何元素。在最後一次迭代, 我們透過將 COUNT 選項的參數設為 1000 , 強制指令為本次迭代掃描更多元素, 從而使得指令傳回的元素也變多了。
基於SCAN的這種安全性,建議大家在生產環境都使用SCAN指令來取代KEYS,不過注意,該指令是在2.8.0版本之後加入的,如果你的Redis低於這個版本,則需要升級Redis。
下面用PHP程式碼示範SCAN指令的使用:
<?php $redis = new Redis(); $redis->connect('127.0.0.1', 6379); /* 设置遍历的特性为不重复查找,该情况下扩展只会scan一次,所以可能会返回空集合 */ $redis->setOption(Redis::OPT_SCAN, Redis::SCAN_NORETRY); $it = NULL; $pattern = '*'; $count = 50; // 每次遍历50条,注意是遍历50条,遍历出来的50条key还要去匹配你的模式,所以并不等于就能够取出50条key do { $keysArr = $redis->scan($it, $pattern, $count); if ($keysArr) { foreach ($keysArr as $key) { echo $key . "\n"; } } } while ($it > 0); //每次调用 Scan会自动改变 $it 值,当$it = 0时 这次遍历结束 退出循环 echo '---------------------------------------------------------------------------------' . "\n"; /* 设置扩展在一次scan没有查找出记录时 进行重复的scan 直到查询出结果或者遍历结束为止 */ $redis->setOption(Redis::OPT_SCAN, Redis::SCAN_RETRY); $it = NULL; $pattern = '*'; $count = 50; // 每次遍历50条,注意是遍历50条,遍历出来的50条key还要去匹配你的模式,所以并不等于就能够取出50条key //这种用法下我们只需要简单判断返回结果是否为空即可, 如果为空说明遍历结束 while ($keysArr = $redis->scan($it, $pattern, $count)) { foreach ($keysArr as $key) { echo $key . "\n"; } }
執行結果:
[root@localhost php]# /usr/local/php/bin/php scan.php bm bm2 h1 name bit bm1 places cities hhl --------------------------------------------------------------------------------- bm bm2 h1 name bit bm1 places cities hhl
注意:如果php执行报错 请升级到较新版本的Redis扩展。
更多redis知识请关注redis入门教程栏目。
以上是redis遍歷所有key的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!