枯燥的程式碼,美麗的人生
熟悉Redis的人都知道,它是單執行緒的(6.0以前版本)。因此在使用一些時間複雜度為O(N)的命令時要非常謹慎。可能一不小心就會阻塞程序,導致Redis出現卡頓。
沒有limit,我們只能一次性獲取所有符合條件的key,如果結果有上百萬條,那麼等待你的就是“無窮無盡”的字串輸出。keys命令是遍歷演算法,時間複雜度是O(N)。如我們剛才所說,這個命令非常容易導致Redis服務卡頓。因此,我們要儘量避免在生產環境使用該命令。Redis官方也進行了明確說明。Warning: consider KEYS as a command that should only be used in production environments with extreme care. It may ruin performance when it is executed against large databases. This command is intended for debugging and special operations, such as changing your keyspace layout. Don't use KEYS in your regular application code. If you're looking for a way to find keys in a subset of your keyspace, consider using sets.
那麼本題目的需求應該如何實現呢?其實redis已經為我們提供了替代方案,直接上程式碼redis_delete_key.py:
# encoding: utf-8 import redisimport randomimport stringimport timeimport sys pool = redis.ConnectionPool(host='127.0.0.1', port=6379, db=0)r = redis.Redis(connection_pool=pool) def del_keys_with_pipe(): start_time = time.time() result_length = 0 pipe = r.pipeline() for key in r.scan_iter(match=sys.argv[1], count=5000): pipe.delete(key) result_length += 1 if result_length % 5000 == 0: pipe.execute() pip_time = time.time() print "use pipeline scan time ", time.time() - start_time pipe.execute() print "use pipeline end at:", time.time() - pip_time print "use pipeline delete numbers:", result_length def main(): del_keys_with_pipe() if __name__ == '__main__': main()
使用時執行命令即可。
python redis_delete_key.py "test_*"
以上程式碼使用python語言,其他語言類似。程式碼中有個關鍵的命令,scan,關於scan 命令介紹大家可以參見文末的官方連結介紹。我們重點來看一下程式碼示例:
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,這表示迭代已經結束了,整個資料集已經被完整遍歷過一遍了。
使用scan查詢字首時,還可以結合pipeline命令進一步提升效能。pipeline指的是管道技術,允許客戶端將多個請求依次發給伺服器,過程中不需要等待請求的回覆,在最後再一併讀取結果即可。其執行過程如下:
傳送命令集 -> 命令排隊 -> 命令執行 -> 返回結果集
當然了,redis cluster模式下的pipeline使用是受限的,感興趣的小夥伴可以自行百度下。
參考文件:
https://redis.io/commands/scan