SCAN及相关SSCAN,HSCAN和ZSCAN命令解析
- j3_liuliang
- 學(xué)習(xí)Redis命令中碰到了SSCAN命令,一時(shí)不知道如何去理解它,所以從Redis中文網(wǎng)上學(xué)習(xí)了一下用法;雖然很多都是復(fù)制粘貼,沒(méi)辦法它寫(xiě)的通俗易懂還詳細(xì)嘛,所以我就順勢(shì)借鑒了一下(有點(diǎn)意思,小伙子!)
相關(guān)文章導(dǎo)航
一、概述
語(yǔ)法:
SCAN cursor [MATCH pattern] [COUNT count]- cursor - 游標(biāo)。
- pattern - 匹配的模式。
- count - 指定從數(shù)據(jù)集里返回多少元素,默認(rèn)值為 10 。
起始版本:2.8.0
時(shí)間復(fù)雜度:O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.
(中文,考慮到有些靚仔英文看不懂!我反正看不懂)O(1)表示每個(gè)調(diào)用。O(N)表示一個(gè)完整的迭代,包括足夠的命令調(diào)用,使光標(biāo)返回到0。N是集合內(nèi)的元素?cái)?shù)。
- SCAN 命令用于迭代當(dāng)前數(shù)據(jù)庫(kù)中的key集合。
- SSCAN 命令用于迭代SET集合中的元素。
- HSCAN 命令用于迭代Hash類(lèi)型中的鍵值對(duì)。
- ZSCAN 命令用于迭代SortSet集合中的元素和元素對(duì)應(yīng)的分值
以上列出的四個(gè)命令都支持增量式迭代,它們每次執(zhí)行都只會(huì)返回少量元素,所以這些命令可以用于生產(chǎn)環(huán)境,而不會(huì)出現(xiàn)像 EYS 或者 SMEMBERS 命令帶來(lái)的可能會(huì)阻塞服務(wù)器的問(wèn)題。
不過(guò),SMEMBERS 命令可以返回集合鍵當(dāng)前包含的所有元素, 但是對(duì)于SCAN這類(lèi)增量式迭代命令來(lái)說(shuō),有可能在增量迭代過(guò)程中,集合元素被修改,對(duì)返回值無(wú)法提供完全準(zhǔn)確的保證。
因?yàn)?SCAN, SSCAN, HSCAN 和 ZSCAN 四個(gè)命令的工作方式都非常相似, 所以這個(gè)文檔會(huì)一并介紹這四個(gè)命令,需要注意的是SSCAN, HSCAN ,ZSCAN命令的第一個(gè)參數(shù)總是一個(gè)key; SCAN 命令則不需要在第一個(gè)參數(shù)提供任何key,因?yàn)樗氖钱?dāng)前數(shù)據(jù)庫(kù)中的所有key。
說(shuō)明:SSCAN,HSCAN,ZSCAN是針對(duì)于SET,HASH,SortSet類(lèi)型的一個(gè)scan擴(kuò)展,用法和scan一樣
所以掌握的SCAN和用法,那么它下面的擴(kuò)展命令還不是收到擒來(lái)
二、SCAN命令基本用法
SCAN命令是一個(gè)基于游標(biāo)的迭代器。這意味著命令每次被調(diào)用都需要使用上一次這個(gè)調(diào)用返回的游標(biāo)作為該次調(diào)用的游標(biāo)參數(shù),以此來(lái)延續(xù)之前的迭代過(guò)程當(dāng)SCAN命令的游標(biāo)參數(shù)被設(shè)置為 0 時(shí), 服務(wù)器將開(kāi)始一次新的迭代, 而當(dāng)服務(wù)器向用戶(hù)返回值為 0 的游標(biāo)時(shí), 表示迭代已結(jié)束。
案例:
127.0.0.1:6379> flushall OK 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 k4 v4 k5 v5 k6 v6 k7 v7 k8 v8 k9 v9 k10 v10 k11 v11 #添加key和值 OK 127.0.0.1:6379> mset k12 v12 k13 v13 k14 v14 k15 v15 k16 v16 k17 v17 k18 v18 k19 v19 k20 v20 OK 127.0.0.1:6379> scan 0 #開(kāi)始第一次遍歷,游標(biāo)為 0 表示開(kāi)始新的遍歷 1) "14" 2) 1) "k8"2) "k11"3) "k2"4) "k19"5) "k14"6) "k13"7) "k4"8) "k10" 9) "k15"10) "k1" 127.0.0.1:6379> scan 14 #繼續(xù)接著上一次遍歷,游標(biāo)設(shè)置上一次返回?cái)?shù)組的第一個(gè)元素值 14 1) "15" 2) 1) "k6"2) "k5"3) "k16"4) "k3"5) "k12"6) "k7"7) "k18"8) "k9"9) "k20"10) "k17" 127.0.0.1:6379> scan 15 #當(dāng)返回?cái)?shù)組的第一個(gè)元素值時(shí)0的時(shí)候表示集合遍歷完畢 1) "0" 2) (empty list or set) 127.0.0.1:6379>在上面這個(gè)例子中, 第一次迭代使用 0 作為游標(biāo), 表示開(kāi)始一次新的迭代。第二次迭代使用的是第一次迭代時(shí)返回的游標(biāo) 14 ,作為新的迭代參數(shù) 。顯而易見(jiàn),SCAN命令的返回值 是一個(gè)包含兩個(gè)元素的數(shù)組在第三次調(diào)用 SCAN 命令時(shí), 命令返回了游標(biāo) 0 , 這表示迭代已經(jīng)結(jié)束, 整個(gè)數(shù)據(jù)集已經(jīng)被完整遍歷過(guò)了。
full iteration :以 0 作為游標(biāo)開(kāi)始一次新的迭代, 一直調(diào)用 SCAN 命令, 直到命令返回游標(biāo) 0 , 我們稱(chēng)這個(gè)過(guò)程為一次完整遍歷。
2.1 SCAN命令的保證
SCAN命令以及其他增量式迭代命令, 在進(jìn)行完整遍歷的情況下可以為用戶(hù)帶來(lái)以下保證:
- 會(huì)遍歷到集合中的每一個(gè)元素(在遍歷期間):從完整遍歷開(kāi)始直到完整遍歷結(jié)束期間, 一直存在于數(shù)據(jù)集內(nèi)的所有元素都會(huì)被完整遍歷返回; 這意味著, 如果有一個(gè)元素, 它從遍歷開(kāi)始直到遍歷結(jié)束期間都存在于被遍歷的數(shù)據(jù)集當(dāng)中, 那么 SCAN 命令總會(huì)在某次迭代中將這個(gè)元素返回給用戶(hù)。
- 不存在集合中的元素不會(huì)遍歷出來(lái)(在遍歷期間):同樣,如果一個(gè)元素在開(kāi)始遍歷之前被移出集合,并且在遍歷開(kāi)始直到遍歷結(jié)束期間都沒(méi)有再加入,那么在遍歷返回的元素集中就不會(huì)出現(xiàn)該元素。
然而因?yàn)樵隽渴矫顑H僅使用游標(biāo)來(lái)記錄迭代狀態(tài), 所以這些命令帶有以下缺點(diǎn):
- 從集合中遍歷出的元素可能會(huì)重復(fù):同一個(gè)元素可能會(huì)被返回多次。 處理重復(fù)元素的工作交由應(yīng)用程序負(fù)責(zé), 比如說(shuō), 可以考慮將迭代返回的元素僅僅用于可以安全地重復(fù)執(zhí)行多次的操作上。
- 遍歷期間添加或刪除集合數(shù)據(jù)時(shí),在這些數(shù)據(jù)也可能會(huì)被返回:如果一個(gè)元素是在迭代過(guò)程中被添加到數(shù)據(jù)集的, 又或者是在迭代過(guò)程中從數(shù)據(jù)集中被刪除的, 那么這個(gè)元素可能會(huì)被返回, 也可能不會(huì)。
2.2 SCAN命令每次執(zhí)行返回的元素?cái)?shù)量
SCAN增量式迭代命令并不保證每次執(zhí)行都返回某個(gè)給定數(shù)量的元素,甚至可能會(huì)返回零個(gè)元素, 但只要命令返回的游標(biāo)不是 0 , 應(yīng)用程序就不應(yīng)該將迭代視作結(jié)束。
不過(guò)命令返回的元素?cái)?shù)量總是符合一定規(guī)則的, 對(duì)于一個(gè)大數(shù)據(jù)集來(lái)說(shuō), 增量式迭代命令每次最多可能會(huì)返回?cái)?shù)十個(gè)元素;而對(duì)于一個(gè)足夠小的數(shù)據(jù)集來(lái)說(shuō), 如果這個(gè)數(shù)據(jù)集的底層表示為編碼數(shù)據(jù)結(jié)構(gòu)(小的sets, hashes and sorted sets), 那么增量迭代命令將在一次調(diào)用中返回?cái)?shù)據(jù)集中的所有元素。
如果需要的話(huà),用戶(hù)可以通過(guò)增量式迭代命令提供的COUNT選項(xiàng)來(lái)指定每次迭代返回元素的最大值。
2.3 COUNT選項(xiàng)
對(duì)于增量式迭代命令不保證每次迭代所返回的元素?cái)?shù)量,我們可以使用COUNT選項(xiàng), 對(duì)命令的行為進(jìn)行一定程度上的調(diào)整。COUNT 選項(xiàng)的作用就是讓用戶(hù)告知迭代命令, 在每次迭代中應(yīng)該從數(shù)據(jù)集里返回多少元素。使用COUNT 選項(xiàng)對(duì)于對(duì)增量式迭代命令相當(dāng)于一種提示, 大多數(shù)情況下這種提示都比較有效的控制了返回值的數(shù)量。
- COUNT 參數(shù)的默認(rèn)值為 10 。
- 數(shù)據(jù)集比較大時(shí),如果沒(méi)有使用MATCH 選項(xiàng), 那么命令返回的元素?cái)?shù)量通常和 COUNT 選項(xiàng)指定的一樣, 或者比 COUNT 選項(xiàng)指定的數(shù)量稍多一些。
- 在迭代一個(gè)編碼為整數(shù)集合(intset,一個(gè)只由整數(shù)值構(gòu)成的小集合)、 或者編碼為壓縮列表(ziplist,由不同值構(gòu)成的一個(gè)小哈希或者一個(gè)小有序集合)時(shí), 增量式迭代命令通常會(huì)無(wú)視 COUNT 選項(xiàng)指定的值, 在第一次迭代就將數(shù)據(jù)集包含的所有元素都返回給用戶(hù)。
注意: 并非每次迭代都要使用相同的 COUNT 值,用戶(hù)可以在每次迭代中按自己的需要隨意改變 COUNT 值, 只要記得將上次迭代返回的游標(biāo)用到下次迭代里面就可以了。
2.4 MATCH 選項(xiàng)
類(lèi)似于KEYS 命令,增量式迭代命令通過(guò)給定 MATCH 參數(shù)的方式實(shí)現(xiàn)了通過(guò)提供一個(gè) glob 風(fēng)格的模式參數(shù), 讓命令只返回和給定模式相匹配的元素。
以下是一個(gè)使用 MATCH選項(xiàng)進(jìn)行迭代的示例:
MATCH功能對(duì)元素的模式匹配工作是在命令從數(shù)據(jù)集中取出元素后和向客戶(hù)端返回元素前的這段時(shí)間內(nèi)進(jìn)行的, 所以如果被迭代的數(shù)據(jù)集中只有少量元素和模式相匹配, 那么迭代命令或許會(huì)在多次執(zhí)行中都不返回任何元素。
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>可以看出,以上的大部分迭代都不返回任何元素。在最后一次迭代, 我們通過(guò)將 COUNT 選項(xiàng)的參數(shù)設(shè)置為 1000 , 強(qiáng)制命令為本次迭代掃描更多元素, 從而使得命令返回的元素也變多了。
2.5 并發(fā)執(zhí)行多個(gè)迭代
在同一時(shí)間, 可以有任意多個(gè)客戶(hù)端對(duì)同一數(shù)據(jù)集進(jìn)行迭代, 客戶(hù)端每次執(zhí)行迭代都需要傳入一個(gè)游標(biāo), 并在迭代執(zhí)行之后獲得一個(gè)新的游標(biāo), 而這個(gè)游標(biāo)就包含了迭代的所有狀態(tài), 因此, 服務(wù)器無(wú)須為迭代記錄任何狀態(tài)。
2.6 中止迭代
因?yàn)榈乃袪顟B(tài)都保存在游標(biāo)里面, 而服務(wù)器無(wú)須為迭代保存任何狀態(tài), 所以客戶(hù)端可以在中途停止一個(gè)迭代, 而無(wú)須對(duì)服務(wù)器進(jìn)行任何通知。即使有任意數(shù)量的迭代在中途停止, 也不會(huì)產(chǎn)生任何問(wèn)題。
2.7 使用錯(cuò)誤的游標(biāo)
使用SCAN 命令傳入間斷的(broken)、負(fù)數(shù)、超出范圍或者其他非正常的游標(biāo)來(lái)執(zhí)行增量式迭代并不會(huì)造成服務(wù)器崩潰, 但可能會(huì)讓命令產(chǎn)生未定義的行為。未定義行為指的是, 增量式命令對(duì)返回值所做的保證可能會(huì)不再為真。 只有兩種游標(biāo)是合法的:
- 在開(kāi)始一個(gè)新的迭代時(shí), 游標(biāo)必須為 0 。
- 增量式迭代命令在執(zhí)行之后返回的, 用于延續(xù)迭代過(guò)程的游標(biāo)。
2.8 迭代能終止的前提
增量式迭代命令所使用的算法只保證在數(shù)據(jù)集的大小有界的情況下, 迭代才會(huì)停止, 換句話(huà)說(shuō), 如果被迭代數(shù)據(jù)集的大小不斷地增長(zhǎng)的話(huà), 增量式迭代命令可能永遠(yuǎn)也無(wú)法完成一次完整迭代。
從直覺(jué)上可以看出, 當(dāng)一個(gè)數(shù)據(jù)集不斷地變大時(shí), 想要訪(fǎng)問(wèn)這個(gè)數(shù)據(jù)集中的所有元素就需要做越來(lái)越多的工作, 能否結(jié)束一個(gè)迭代取決于用戶(hù)執(zhí)行迭代的速度是否比數(shù)據(jù)集增長(zhǎng)的速度更快。
2.9 返回值
SCAN, SSCAN, HSCAN 和 ZSCAN 命令都返回一個(gè)包含兩個(gè)元素的 multi-bulk 回復(fù): 回復(fù)的第一個(gè)元素是字符串表示的無(wú)符號(hào) 64 位整數(shù)(游標(biāo)), 回復(fù)的第二個(gè)元素是另一個(gè) multi-bulk 回復(fù), 包含了本次被迭代的元素。
- SCAN 命令返回的每個(gè)元素都是一個(gè)key。
- SSCAN 命令返回的每個(gè)元素都是一個(gè)集合成員。
- HSCAN 命令返回的每個(gè)元素都是一個(gè)鍵值對(duì),一個(gè)鍵值對(duì)由一個(gè)鍵和一個(gè)值組成。
- ZSCAN命令返回的每個(gè)元素都是一個(gè)有序集合元素,一個(gè)有序集合元素由一個(gè)成員(member)和一個(gè)分值(score)組成。
2.10 另外的例子
迭代hash中的鍵值對(duì):
127.0.0.1:6379> hmset vipclient name j3_liuliang age 18 #添加hash類(lèi)型數(shù)據(jù) OK 127.0.0.1:6379> hscan vipclient 0 #開(kāi)始迭代 1) "0" 2) 1) "name"2) "j3_liuliang"3) "age"4) "18" 127.0.0.1:6379>結(jié)束語(yǔ)
- 本文結(jié)合Redis中文網(wǎng)和博主的實(shí)踐案例及理解所寫(xiě),算是一種擴(kuò)展把對(duì)Redis的命令
- 由于博主才疏學(xué)淺,難免會(huì)有紕漏,假如你發(fā)現(xiàn)了錯(cuò)誤或偏見(jiàn)的地方,還望留言給我指出來(lái),我會(huì)對(duì)其加以修正。
- 如果你覺(jué)得文章還不錯(cuò),你的轉(zhuǎn)發(fā)、分享、點(diǎn)贊、留言就是對(duì)我最大的鼓勵(lì)。
- 感謝您的閱讀,十分歡迎并感謝您的關(guān)注。
總結(jié)
以上是生活随笔為你收集整理的SCAN及相关SSCAN,HSCAN和ZSCAN命令解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: EJB-应用创造中
- 下一篇: c oracle udt,c#调用Ora