Redis查詢指令 SCAN

2021-10-03 00:23:23 字數 3250 閱讀 1967

目錄

1、keys鍵命令缺點

2、引入scan命令

3、scan使用

4、更多scan指令

5、允許中途停止迭代

6、迭代什麼時候終結

7、時間複雜度

redis 提供了乙個簡單暴力的指令 keys 用來列出所有滿足特定正則字串規則的key。keys指令使用非常簡單,提供乙個簡單的正則字串即可,但是有很明顯的兩個缺點:

1)沒有 offset、limit 引數,一次性吐出所有滿足條件的 key,如果例項中有幾百萬個key滿足條件,那就可能導致滿屏的字串刷的沒有盡頭;

2)keys演算法是遍歷演算法,複雜度是 o(n),如果例項中有千萬級以上的 key,這個指令就會導致redis服務卡頓,甚至造成阻塞,因為redis是單執行緒程式,順序執行所有指令,其它指令必須等到當前的 keys 指令執行完了才可以繼續。

所以,生產環境一般是遮蔽keys命令的。

scan命令是乙個基於游標的迭代器。這裡的意思是:命令每次被呼叫都需要使用上一次該呼叫返回的游標作為本次呼叫的游標引數,以此來延續之前的迭代過程。當設定scan命令的游標引數為0時,伺服器將開始一次新的迭代;而當redis伺服器向使用者返回值為0的游標時,

表示迭代已結束,這是唯一迭代結束的判定方式,而不能通過返回結果集是否為空判斷迭代結束。

scan相比keys具備有以下優點:

1)複雜度雖然也是 o(n),但是它是通過游標分步進行的,不會阻塞執行緒;

2)提供 limit 引數,可以控制每次返回結果的最大條數,limit 只是對增量式迭代命令的一種提示(hint),返回的結果可多可少;

3)伺服器不需要為游標儲存狀態,游標的唯一狀態就是 scan 返回給客戶端的游標整數;

------------

scan也有缺點:

1)返回的結果可能會有重複,需要客戶端去重複,這點非常重要;

2)遍歷的過程中如果有資料修改,改動後的資料能不能遍歷到是不確定的。即如果乙個元素是在迭代過程中被新增到資料集的, 又或者是在迭代過程中從資料集中被刪除的, 那麼這個元素可能會被返回, 也可能不會, 這是未定義未知的。

3)單次返回的結果是空的並不意味著遍歷結束,而要看返回的游標值是否為零

redis-cli scan [cursor] match [pattern] count [limit]

1、提供3個引數:

cursor整數值  使用者將游標設定為0,表示開始新一次的迭代

pattern正規表示式

count limit 

預設10 

注意這裡的limit並不是限定返回結果的數量,而是限定伺服器單次遍歷的字典槽位數)

注意並非每次迭代都要使用相同的 count 值。使用者可以在每次迭代中按自己的需要隨意改變 count 值, 只要記得將上次迭代返回的游標用到下次迭代裡面就可以了

使用了錯誤的游標。使用間斷的(broken)、負數、超出範圍或者其他非正常的游標來執行增量式迭代並不會造成伺服器崩潰, 但可能會讓命令產生未定義的行為。

游標的合法值只有2個:

在開始乙個新的迭代時, 游標必須為0;

使用前一次迭代命令返回的迭代游標值。

2、返回值:

下一次迭代游標

本次迭代結果集(有可能為空)

3、scan過程:

第一次遍歷時,cursor 值為0,後續將返回結果中第乙個整數值作為下一次遍歷的cursor。一直遍歷到redis返回的游標值為0時結束。

以0 作為游標開始一次新的迭代, 一直呼叫 scan 命令, 直到命令返回游標 0 , 我們稱這個過程為一次完整遍歷。

4、scan指令例項:

$ redis-cli scan 0 match key99* count 1000

1) "13912"

2) 1) "key997"

2) "key9906"

3) "key9957"

4) "key9902"

5) "key9971"

6) "key9935"

7) "key9958"

8) "key9928"

9) "key9931"

10) "key9961"

11) "key9948"

12) "key9965"

13) "key9937"

$ redis-cli scan 13912 match key99* count 1000

1) "5292"

2) 1) "key996"

2) "key9960"

3) "key9973"

4) "key9978"

5) "key9927"

6) "key995"

7) "key9992"

從上面的過程可以看到雖然設定的limit是1000,但是返回的結果只有 10 個左右。這是因為因為這個 limit 不是限定返回結果的數量,而是限定伺服器單次遍歷的字典槽位數量(約等於)。所以如果將limit 設定為 10,你會發現返回結果是空的,但是游標值不為零,意味著遍歷還沒結束。

如果將limit設定為10,例如下:

$ redis-cli scan 0 match key99* count 10

1) "15360"

2) (empty list or set)

$ redis-cli scan 15360 match key99* count 10

1) "2304"

2) (empty list or set)

scan 指令是一系列指令,除了可以遍歷所有的 key 之外,還可以對指定的容器集合進行遍歷。』

注意,sscan 命令、 hscan 命令和 zscan 命令的第乙個引數總是乙個資料庫鍵。而 scan 命令則不需要在第乙個引數提供任何資料庫鍵 —— 因為它迭代的是當前資料庫中的所有資料庫鍵。

因為迭代的所有狀態都儲存在游標裡面, 而伺服器無須為迭代儲存任何狀態, 所以客戶端可以在中途停止乙個迭代, 而無須對伺服器進行任何通知。即使有任意數量的迭代在中途停止, 也不會產生任何問題。

當redis伺服器向使用者返回值為0的游標時,表示迭代已結束,這是唯一迭代結束的判定方式,而不能通過返回結果集是否為空判斷迭代結束。

同時增量式迭代命令所使用的演算法只保證在資料集的大小有界(bounded)的情況下, 迭代才會停止, 換句話說, 如果被迭代資料集的大小不斷地增長的話, 增量式迭代命令可能永遠也無法完成一次完整迭代。

每次執行的複雜度為 o(1),對資料集進行一次完整迭代的複雜度為 o(n),其中 n 為資料集中的元素數量。

8、參考資料

Redis簡單實踐 掃瞄指令scan

redis在應用中的存在一般是以快取的形式,但是在某些應用場景也可能會涉及到需要拿出大量keys的情況,一般全盤掃瞄只需要使用keys 就可以拿出所有的key,但是keys指令有很明顯的缺陷。1.沒有sql中類似offset等指令,無法分批 2.keys是直接遍歷,複雜度o n 全表數量大會造成整個...

《Redis深度歷險》scan

redis中的keys命令可以列出滿足特定正規表示式所有的key.命令的格式為keys pattern 但是它存在倆顯著的缺點 為解決此問題,2.8版本便加入年scan指令。它有如下特點 基本用法 scan cursor match pattern count count cursor為設定的游標值...

Redis的Scan粗略理解

最近在了解redis的scan命令,scan就相當於分段遍歷,遍歷過程 現rehash也能保證scan不重複和不遺漏,這兩天了解這部分的原理,順便記錄一下。參考於redisscan迭代器遍歷操作原理 二 先說順序遍歷的問題,也就是按0,1,2,3 的順序,用例子說明,當遍歷完槽2的時候,返回下乙個遍...