?
This document uses PHP Chinese website manual Release
SCAN cursor [MATCH pattern] [COUNT count]
自2.8.0起可用。
時(shí)間復(fù)雜度: O(1)用于每個(gè)呼叫。O(N)進(jìn)行完整的迭代,包括足夠的命令調(diào)用以使游標(biāo)返回0. N是集合中元素的數(shù)量。
使用 SCAN 命令和密切相關(guān)的命令 SSCAN,HSCAN 和 ZSCAN 來(lái)遞增地遍歷一組元素。
SCAN 迭代當(dāng)前選定的 Redis 數(shù)據(jù)庫(kù)中的一組鍵。
SSCAN 迭代 Sets 類型的元素。
HSCAN 迭代哈希類型的字段及其關(guān)聯(lián)值。
ZSCAN 迭代 Sorted Set 類型的元素及其相關(guān)分?jǐn)?shù)。
由于這些命令允許增量迭代,每次調(diào)用只返回少量元素,因此可以在生產(chǎn)中使用它們,而無(wú)需像 KEYS 或 SMEMBERS 這樣的命令可能會(huì)在被調(diào)用時(shí)長(zhǎng)時(shí)間(甚至幾秒)阻塞服務(wù)器的缺點(diǎn)鍵或元素的大集合。
然而,盡管像 SMEMBERS 這樣的阻塞命令能夠在給定時(shí)刻提供集合中的所有元素,但 SCAN 系列命令僅對(duì)返回的元素提供有限的保證,因?yàn)槲覀冞f增迭代的集合可能在迭代過(guò)程中發(fā)生更改。
請(qǐng)注意,SCAN,SSCAN,HSCAN 和 ZSCAN 的工作方式非常相似,因此本文檔涵蓋了所有四個(gè)命令。然而,一個(gè)明顯的區(qū)別是,對(duì)于SSCAN,HSCAN 和 ZSCAN,第一個(gè)參數(shù)是保存 Set,Hash 或 Sorted Set 值的密鑰的名稱。SCAN 命令不需要任何鍵名參數(shù),因?yàn)樗诋?dāng)前數(shù)據(jù)庫(kù)中迭代鍵,所以迭代對(duì)象就是數(shù)據(jù)庫(kù)本身。
SCAN 是一個(gè)基于游標(biāo)的迭代器。這意味著在每次調(diào)用該命令時(shí),服務(wù)器都會(huì)返回一個(gè)更新的游標(biāo),用戶需要在下一次調(diào)用中將其用作游標(biāo)參數(shù)。
當(dāng)光標(biāo)設(shè)置為0時(shí)開(kāi)始迭代,當(dāng)服務(wù)器返回的光標(biāo)為0時(shí)終止迭代。以下是 SCAN 迭代的示例:
redis 127.0.0.1:6379> scan 01) "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 171) "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"
在上面的例子中,第一個(gè)調(diào)用使用零作為游標(biāo),以開(kāi)始迭代。第二次調(diào)用使用前一次調(diào)用返回的游標(biāo)作為回復(fù)的第一個(gè)元素,即17。
正如你所看到的,SCAN返回值 是一個(gè)包含兩個(gè)值的數(shù)組:第一個(gè)值是下一次調(diào)用中使用的新游標(biāo),第二個(gè)值是元素?cái)?shù)組。
由于在第二次調(diào)用中返回的游標(biāo)是0,所以服務(wù)器向調(diào)用者發(fā)信號(hào)通知完成迭代,并且集合被完全探索。使用游標(biāo)值0開(kāi)始迭代,并調(diào)用 SCAN,直到返回的游標(biāo)再次為0,稱為完整迭代。
SCAN 命令和 SCAN 系列中的其他命令能夠向用戶提供與完整迭代關(guān)聯(lián)的一組保證。
完整迭代總是從完整迭代的開(kāi)始到結(jié)束檢索集合中存在的所有元素。這意味著如果迭代開(kāi)始時(shí)給定元素位于集合內(nèi)部,并且在迭代終止時(shí)仍然存在,那么在某個(gè)點(diǎn) SCAN 將其返回給用戶。
完整迭代從不會(huì)返回集合中不存在的任何元素,從完整迭代的開(kāi)始到結(jié)束。因此,如果一個(gè)元素在迭代開(kāi)始之前被移除,并且在迭代過(guò)程中永遠(yuǎn)不會(huì)將其添加回集合中,SCAN可以確保這個(gè)元素永遠(yuǎn)不會(huì)被返回。
但是由于 SCAN 只有很少的狀態(tài)相關(guān)(只是光標(biāo)),它有以下缺點(diǎn):
給定的元素可能會(huì)多次返回。應(yīng)用程序可以處理重復(fù)元素的情況,例如僅使用返回的元素來(lái)執(zhí)行多次重新應(yīng)用時(shí)安全的操作。
在整個(gè)迭代過(guò)程中并不總是出現(xiàn)在集合中的元素可能被返回或不被返回:它是未定義的。
SCAN 家族功能不保證每次通話返回的元素?cái)?shù)量都在給定的范圍內(nèi)。這些命令還允許返回零個(gè)元素,并且只要返回的游標(biāo)不為零,客戶端就不應(yīng)該考慮迭代完成。
然而,返回的元素的數(shù)量是合理的,也就是說(shuō),實(shí)際上,SCAN 可能會(huì)在迭代大集合時(shí)返回?cái)?shù)十個(gè)元素的最大數(shù)量的元素,或者可能會(huì)將集合中的所有元素一次返回當(dāng)?shù)献銐蛐∫员阍趦?nèi)部表示為編碼數(shù)據(jù)結(jié)構(gòu)(這發(fā)生在小集合,散列和有序集合)時(shí)調(diào)用。
但是,用戶可以使用 COUNT 選項(xiàng)調(diào)整每次呼叫返回元素?cái)?shù)量級(jí)的順序。
雖然 SCAN 不提供有關(guān)每次迭代返回的元素?cái)?shù)量的保證,但可以使用 COUNT 選項(xiàng)憑經(jīng)驗(yàn)調(diào)整 SCAN 的行為?;旧嫌? COUNT,用戶指定了每次調(diào)用應(yīng)該完成的工作量,以便從集合中檢索元素。這只是實(shí)現(xiàn)的一個(gè)暗示,但是一般來(lái)說(shuō),這是您實(shí)施過(guò)程中大部分時(shí)間所期望的。
COUNT 的默認(rèn)值是10。
當(dāng)?shù)荑€空間,或者一個(gè)足夠大的集合,哈?;蚺判蚣?,以便用哈希表表示時(shí)(假設(shè)沒(méi)有使用 MATCH 選項(xiàng)),服務(wù)器通常會(huì)返回計(jì)數(shù)或比每次調(diào)用的計(jì)數(shù)元素多一點(diǎn)。
迭代編碼為 intsets 的集合(由整數(shù)組成的小集合)或編碼為 ziplists 的哈希和排序集(小哈希和由小個(gè)別值組成的集合)時(shí),通常所有元素都在第一個(gè) SCAN 調(diào)用中返回,而不管 COUNT 值。
重要提示:每次迭代都不需要使用相同的 COUNT 值。調(diào)用者可以根據(jù)需要自由地將計(jì)數(shù)從一次迭代更改為另一次迭代,只要在下次調(diào)用中傳遞的游標(biāo)是在先前對(duì)該命令的調(diào)用中獲得的游標(biāo)。
只能迭代匹配給定全局樣式模式的元素,類似于只將模式作為參數(shù)的 KEYS 命令的行為。
為此,只需MATCH <pattern>
在 SCAN 命令末尾附加參數(shù)(它可與所有 SCAN 系列命令一起使用)。
這是一個(gè)使用 MATCH 進(jìn)行迭代的例子:
redis 127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood(integer) 6redis 127.0.0.1:6379> sscan myset 0 match f*1) "0"2) 1) "foo" 2) "feelsgood" 3) "foobar"redis 127.0.0.1:6379>
重要的是要注意,在將數(shù)據(jù)返回給客戶端之前,在從集合中檢索元素之后應(yīng)用 MATCH 過(guò)濾器。這意味著如果模式匹配集合中很少的元素,SCAN 很可能在大多數(shù)迭代中都不返回元素。一個(gè)例子如下所示:
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 10001) "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>
正如您所看到的,大部分調(diào)用都返回了零個(gè)元素,但是最后一次調(diào)用的 COUNT 為1000,以強(qiáng)制命令為該迭代執(zhí)行更多掃描。
無(wú)限數(shù)量的客戶端可能會(huì)同時(shí)迭代同一個(gè)集合,因?yàn)榈鞯耐暾麪顟B(tài)在游標(biāo)中,每次調(diào)用都會(huì)獲取并返回給客戶端。服務(wù)器端根本沒(méi)有狀態(tài)。
由于沒(méi)有狀態(tài)服務(wù)器端,但全狀態(tài)由光標(biāo)捕獲,因此調(diào)用者可以自由地在半途中終止一次迭代,而無(wú)需以任何方式將此信號(hào)通知給服務(wù)器。無(wú)限次的迭代可以開(kāi)始,并且不會(huì)在沒(méi)有任何問(wèn)題的情況下終止。
調(diào)用帶有破損,負(fù)值,超范圍或其他無(wú)效光標(biāo)的 SCAN 將導(dǎo)致未定義的行為,但不會(huì)導(dǎo)致崩潰。未定義的是,對(duì)于返回元素的保證不能再由 SCAN 實(shí)現(xiàn)來(lái)保證。
唯一有效的游標(biāo)是:
開(kāi)始迭代時(shí)光標(biāo)值為0。
前一次調(diào)用 SCAN 返回的光標(biāo)為了繼續(xù)迭代。
SCAN 算法只有在迭代集合的大小保持限定為給定的最大大小時(shí)才被保證終止,否則迭代總是增長(zhǎng)的集合可能導(dǎo)致 SCAN 永遠(yuǎn)不會(huì)終止完整迭代。
這很容易直觀地看到:如果集合增長(zhǎng),為了訪問(wèn)所有可能的元素需要做更多的工作,并且終止迭代的能力取決于 SCAN 調(diào)用的次數(shù)和它的 COUNT 選項(xiàng)值,與收藏增長(zhǎng)的速度。
SCAN,SSCAN,HSCAN 和 ZSCAN 返回一個(gè)雙元素多批量回復(fù),其中第一個(gè)元素是一個(gè)表示無(wú)符號(hào)64位數(shù)字(游標(biāo))的字符串,第二個(gè)元素是具有元素?cái)?shù)組的多個(gè)批量。
SCAN 數(shù)組元素是一個(gè)鍵列表。
SSCAN 元素?cái)?shù)組是 Set 成員的列表。
對(duì)于 Hash 的每個(gè)返回元素,HSCAN 元素?cái)?shù)組包含兩個(gè)元素,一個(gè)字段和一個(gè)值。
對(duì)于有序集合的每個(gè)返回元素,ZSCAN 元素?cái)?shù)組包含兩個(gè)元素,一個(gè)成員及其相關(guān)分?jǐn)?shù)。
迭代一個(gè)哈希值。
redis 127.0.0.1:6379> hmset hash name Jack age 33 OK redis 127.0.0.1:6379> hscan hash 0 1) "0" 2) 1) "name" 2) "Jack" 3) "age" 4) "33"