1. 程式人生 > >Redis命令詳解:Keys

Redis命令詳解:Keys

介紹完Redis連線相關命令後,再來介紹一下與Key相關的命令,Redis作為一個key-value資料庫,對Key進行操作是無法避免的。

DEL

最早可用版本1.0.0

刪除指定的鍵值對,如果指定的key不存在,則忽略。DEL命令的時間複雜度是O(N),對於除字串外的其他資料型別,命令的時間複雜度為O(M),M是值的元素的個數。所以,在生產環境儘量避免一次性刪除過多複雜資料型別的操作。

127.0.0.1:6379> SET key1 "jackey"
OK
127.0.0.1:6379> SET key2 "zhe"
OK
127.0.0.1:6379> DEL key1 key2 key3
(
integer) 2

DUMP

最早可用版本2.6.0

使用一種Redis的格式序列化指定鍵儲存的值。可用使用RESTORE命令將這個值反序列化。

這種序列化格式有以下3個特點:

  • 它包含有64位的校驗和,用於錯誤檢查,RESTORE命令在反序列化之前會先檢查校驗和
  • 值的編碼格式和RDB檔案的編碼格式相同
  • RDB的版本會被序列化到值中,因此,不同版本的Redis可能會因為不相容RDB版本而拒絕反序列化

序列化的值不包含過期時間的相關資訊,可以使用PTTL命令獲取當前值的存活時間。如果值不存在則會返回nil

127.0.0.1:6379> SET key1 "jackey"
OK
127.0.0.1:6379>
DUMP key1 "\x00\x06jackey\b\x00\xec\x89'G'X\xfc:" 127.0.0.1:6379> DUMP not-exist-key (nil)

DUMP時間複雜度分為兩部分:訪問key值的時間複雜度為O(1),而序列化值的時間複雜度為O(N*M),N是組成值的元素的數量,M是元素的平均大小。如果序列化比較短的字串,則該命令的時間複雜度可以看做O(1)。

EXISTS

最早可用版本1.0.0

用於判斷key是否存在。3.0.3版本以後支援多引數,即可以一次性判斷多個key,返回值是存在的key的數量。對於判斷單個key是否存在,會返回1或者0,因此,該命令是向後相容的。

需要注意的是:如果引數中有重複的存在命令,則返回結果不會去重。

127.0.0.1:6379> SET key1 "jackey"
OK
127.0.0.1:6379> SET key2 "zhe"
OK
127.0.0.1:6379> EXISTS key1
(integer) 1
127.0.0.1:6379> EXISTS not-exist-key
(integer) 0
127.0.0.1:6379> EXISTS key1 key2 not-exist-key
(integer) 2
127.0.0.1:6379> EXISTS key1 key1 key1
(integer) 3

EXPIRE

最早可用版本1.0.0

為指定的key設定存活時間。存活時間會被DEL,SET,GETSET和所有的STORE命令刪除或者覆蓋。如果我們只修改key的值而不修改存活時間或者儲存到一個新的key中,則原來的key的存活時間保持不變。如果使用RENAME對一個key重新命名,那麼原有key的存活時間會賦給新的key。

如果想要清除存活時間,使指定的key成為一個永久的key,則可以使用PERSIST命令,我們稍後會詳細介紹這個命令。

如果使用EXPIRE/PEXPIRE為某個key設定的存活時間為非正數,或者使用EXPIREAT/PEXPIREAT設定了一個過去的時間,則這個key會直接被刪除。

127.0.0.1:6379> EXPIRE key1 -1
(integer) 1
127.0.0.1:6379> EXISTS key1
(integer) 0

對一個已經有存活時間的key再次使用EXPIRE設定存活時間,則將key的存活時間更新,在許多應用中我們都會用到這一點。

注意:在Redis的2.1.3版本之前,如果修改一個帶有存活時間的key的值,則會刪除整個key。

關於時間精度,Redis2.4版本中,一個key過期的一秒內仍可以訪問,而到了2.6版本,這一時間已經被精確到了1毫秒。因為從2.6版本開始,存活時間儲存的是絕對時間(Unix的時間戳),而這就意味著,你的計算機的時間需要保證可靠,如果你將RDB檔案放到另一臺機器上載入,當這兩臺機器的時間差距較大時,你就會發現可能有些key被刪除了或者有些key的存活時間被延長了。

下面我們在來討論一下Redis究竟是如何使key過期的,Redis的過期策略有兩種:一種是被動的,一種是主動的。

被動過期就是當客戶端訪問某個key,服務端會去檢查這個key的存活時間,判斷是否過期。當然,這種過期策略存在一定的問題,如果某個key一直都不訪問,就不會被發現它過期了,那麼它將永遠“苟活”在記憶體中。所以Redis會定期隨機的檢視被設定過存活時間的key,看它們是否過期,如果過期了,就會及時清理掉。Redis每秒會做10次下面的操作:

  1. 隨機檢視20個設定過存活時間的key(從設定存活時間的set中取)
  2. 刪除所有過期的key
  3. 如果過期的key超過25%,那麼會從第一步開始再執行一次

EXPIREAT

最早可用版本1.2.0

此命令和EXPIRE的作用相同,不同之處是它的引數需要傳Unix時間戳(即從1970年1月1日起的毫秒數)。

127.0.0.1:6379> GET key2
"zhe"
127.0.0.1:6379> EXPIREAT key2 1537733374
(integer) 1
127.0.0.1:6379> TTL key2
(integer) 12960

KEYS

最早可用版本1.0.0

這個命令會返回匹配到的所有key,時間複雜度為O(N)。在官方文件中說,在入門級的膝上型電腦上,Redis掃描100萬條key只需要40毫秒,但是我們仍然要避免在生產環境使用這個命令。特別是千萬不要使用KEYS *這樣的命令,因為你不知道生產環境存在多少key,這樣的命令有可能使你的生產環境的Redis陷入很長一段時間的不可用狀態。所以,請馬上刪除應用層程式碼中的KEYS命令或者抓緊時間更新自己的簡歷。

如果需要查詢key,可以使用SCAN命令或者sets命令。

雖然我們非常不建議使用KEYS命令,但是它的匹配策略還是要介紹一下的:

?是單個字元的萬用字元,*是任意個數的萬用字元,[ae]會匹配到a或e,^e表示不匹配e,a-c表示匹配a或b或c,特殊符號使用\隔開。

127.0.0.1:6379> MSET key1hello jackey key2hello zhe age 3
OK
127.0.0.1:6379> KEYS key?hello
1) "key1hello"
2) "key2hello"
127.0.0.1:6379> KEYS k*
1) "key1hello"
2) "key2hello"
127.0.0.1:6379> KEYS *age*
1) "age"
127.0.0.1:6379> KEYS *
1) "age"
2) "key1hello"
3) "key2hello"

MIGRATE

最早可用版本2.6.0

這個命令用來將源例項的key以原子操作傳輸到目標例項,然後將源例項的key刪除。相當於在源例項執行了DUMP+DEL操作,在目標例項執行了RESTORE操作。這一操作會阻塞進行傳輸的兩個例項,在傳輸過程中,key總會存在於一個例項中,除非發生超時錯誤。在3.2版本以後,MIGRATE可以將多個key作為管線一次性傳輸。

在執行MIGRATE命令時,必須要設定一個超時時間,如果到了超時時間命令仍未執行完,則會丟擲一個IOERR。但返回這個錯誤時,兩個例項的狀態可能有兩種:要麼兩個例項都存在指定的key,要麼只有源例項存在指定的key。總之,key是不會丟失的。

從3.0.6版本開始,MIGRATE支援一次傳輸多個key,為了保證不過載或者出現環形操作,MIGRATE需要使用KEYS引數,而原來指定的key的引數要被設定為空字串。

MIGRATE 192.168.1.34 6379 "" 0 5000 KEYS key1 key2 key3

這裡還有兩個選填引數需要介紹:一個是COPY,加上這個引數的話,傳輸完成後不會刪除源例項中的key。另一個是REPLACE,這個引數的作用是替換目標例項已存在的key。這兩個引數在3.0版本以後才可以使用。

MOVE

最早可用版本1.0.0

不知道大家還記不記得前文中我們提到過的SELECT命令,SELECT用來切換資料庫。使用MOVE命令就是將當前資料庫的key移動到指定的資料庫中,如果指定庫中已經存在這個key或者當前庫不存在這個key,那麼這個命令什麼也不做。

127.0.0.1:6379> KEYS *
1) "age"
2) "key1hello"
3) "key2hello"
127.0.0.1:6379> MOVE age 1
(integer) 1
127.0.0.1:6379> KEYS *
1) "key1hello"
2) "key2hello"
127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]> KEYS *
1) "age"

OBJECT

最早可用版本2.2.3

OBJECT用來檢視Redis物件內部的相關資訊。這一命令在除錯時經常被使用。下面我們來介紹OBJECT命令的具體用法:

  • OBJECT REFCOUNT key:返回指定key的值的引用數量
  • OBJECT ENCODING key:返回指定key的內部儲存使用的編碼格式
  • OBJECT IDLETIME key:返回指定key的空閒時間(有多長時間沒有被讀寫),目前最小精度為10秒,這一命令經常在Redis淘汰機制中使用(淘汰策略為LRU或noeviction)
  • OBJECT FREQ key:返回指定key訪問頻率的對數,當淘汰策略為LFU時,這一命令會被用到
  • OBJECT HELP:返回幫助資訊

物件的編碼格式也有很多種:

  • Strings會被編碼為raw或int
  • Lists會被編碼為ziplist或linkedlist
  • Sets會被編碼為intset或hashtable
  • Hashs會被編碼為ziplist或hashtable
  • Sorted Sets會被編碼為ziplist或skiplist
127.0.0.1:6379> OBJECT REFCOUNT key1hello
(integer) 1
127.0.0.1:6379> OBJECT IDLETIME key2hello
(integer) 3637
127.0.0.1:6379> OBJECT ENCODING age
"int"

PERSIST

最早可用版本2.2.0

刪除指定key的過期時間,使之變成永久的key。

PEXPIRE

最早可用版本2.6.0

PEXPIRE的作用和EXPIRE一樣,只不過引數中的時間單位是毫秒。

PEXPIREAT

最早可用版本2.6.0

作用和EXPIREAT相同,引數同樣是毫秒。

PTTL

最早可用版本2.6.0

返回指定key的剩餘存活時間的毫秒數。2.8以後的版本返回值有些變化,如果key不存在,則返回-2;如果key是永久的,則返回-1。

RANDOMKEY

最早可用版本1.0.0

此命令用於從當前資料庫返回一個隨機的key。

RENAME

最早可用版本1.0.0

重新命名一個key。如果key不存在,則會返回錯誤。而如果新的key已經存在,則此命令會覆蓋原來的key(它其實是執行了一個隱式的DEL命令,因此如果原來的key儲存的物件很大的話, 刪除操作延時會很高)。在3.2版本以前,如果源key和目標key相同的話,會報錯。

RENAMENX

如果新的key不存在的話,重新命名key,如果存在的話返回0,成功返回1。

RESTORE

最早可用版本2.6.0

用法:RESTORE key ttl serialized-value [REPLACE]

此命令是將一組資料反序列化,並存到key。如果ttl是0,則key是永久的。在Redis3.0版本以後,如果不使用REPLACE引數並且key已經存在,則會返回一個錯誤“Target key name is busy”。

SCAN

最早可用版本2.8.0

用法:SCAN cursor MATCH pattern COUNT count

其中cursor為遊標,MATCH和COUNT為可選引數。

SCAN命令和SSCAN、HSCAN、ZSCAN命令都用於增量的迭代元素集,它每次返回小部分資料,不會像KEYS那樣阻塞Redis。SCAN命令是基於遊標的,每次呼叫後,都會返回一個遊標,用於下一次迭代。當遊標返回0時,表示迭代結束。

SCAN每次返回的數量並不固定,也有可能返回資料為空。另外,SCAN命令和KEYS命令一樣支援匹配。

我們在Redis裡存入10000個key用於測試。

結果如下:

127.0.0.1:6379> scan 0 match key24* count 1000
1) "1688"
2) 1) "key2411"
   2) "key2475"
   3) "key2494"
   4) "key2406"
   5) "key2478"
127.0.0.1:6379> scan 1688 match key24* count 1000
1) "2444"
2)  1) "key2458"
    2) "key249"
    3) "key2407"
    4) "key2434"
    5) "key241"
    6) "key2497"
    7) "key2435"
    8) "key2413"
    9) "key2421"
   10) "key248"
127.0.0.1:6379> scan 2444 match key24* count 1000
1) "818"
2)  1) "key2459"
    2) "key2462"
    3) "key2409"
    4) "key2454"
    5) "key2431"
    6) "key2423"
    7) "key2476"
    8) "key2428"
    9) "key2493"
   10) "key2420"
127.0.0.1:6379> scan 818 match key24* count 1000
1) "9190"
2)  1) "key2402"
    2) "key2415"
    3) "key2429"
    4) "key2424"
    5) "key2425"
    6) "key2400"
    7) "key2472"
    8) "key2479"
    9) "key2448"
   10) "key245"
   11) "key2487"
   12) "key2430"
   13) "key2405"
127.0.0.1:6379> scan 9190 match key24* count 1000
1) "12161"
2)  1) "key2488"
    2) "key2437"
    3) "key2404"
    4) "key2440"
    5) "key2461"
    6) "key2416"
    7) "key2436"
    8) "key2403"
    9) "key2460"
   10) "key2452"
   11) "key2449"
   12) "key2482"
127.0.0.1:6379> scan 12161 match key24* count 1000
1) "11993"
2)  1) "key2483"
    2) "key2491"
    3) "key242"
    4) "key2466"
    5) "key2446"
    6) "key2465"
    7) "key243"
    8) "key2438"
    9) "key2457"
   10) "key246"
   11) "key2422"
   12) "key2418"
127.0.0.1:6379> scan 11993 match key24* count 1000
1) "7853"
2) 1) "key2498"
   2) "key2451"
   3) "key2439"
   4) "key2495"
   5) "key2408"
   6) "key2410"
127.0.0.1:6379> scan 7853 match key24* count 1000
1) "5875"
2)  1) "key2486"
    2) "key2490"
    3) "key244"
    4) "key2401"
    5) "key2463"
    6) "key2481"
    7) "key2477"
    8) "key2468"
    9) "key2433"
   10) "key2489"
   11) "key2455"
   12) "key2426"
   13) "key24"
   14) "key2450"
   15) "key2414"
   16) "key2442"
   17) "key2473"
   18) "key2467"
   19) "key2469"
   20) "key2456"
127.0.0.1:6379> scan 5875 match key24* count 1000
1) "14311"
2)  1) "key2453"
    2) "key2492"
    3) "key2480"
    4) "key2427"
    5) "key2443"
    6) "key2417"
    7) "key2432"
    8) "key240"
    9) "key2445"
   10) "key2484"
   11) "key2444"
   12) "key247"
   13) "key2485"
127.0.0.1:6379> scan 14311 match key24* count 1000
1) "16383"
2)  1) "key2441"
    2) "key2474"
    3) "key2447"
    4) "key2471"
    5) "key2470"
    6) "key2464"
    7) "key2412"
    8) "key2419"
    9) "key2499"
   10) "key2496"
127.0.0.1:6379> scan 16383 match key24* count 1000
1) "0"
2) (empty list or set)

可以看到雖然我們設定的count為1000,但Redis每次返回的數值只有10個左右。

SORT

最早可用版本1.0.0

當有N個元素需要排序,並且要返回M個元素時,SORT命令的時間複雜度為O(N+M*log(M))

此命令用於返回或儲存list,set和sorted set的鍵,預設將數字或者可排序的key進行排序,Redis會將其視為雙精度浮點數。

如果想要對字串按字典順序排序,可以使用ALPHA引數。

如果想要按照外部欄位進行排序,可以使用BY引數。

TOUCH

最早可用版本3.2.1

修改某一個或多個key的最後訪問時間,如果key不存在,則忽略。

TTL

最早可用版本1.0.0

返回指定key的剩餘存活時間,單位為秒。

在2.6版本及以前,如果key不存在或者是永久key,都會返回-1。從2.8版本開始,如果key不存在,則返回-2,如果key為永久key,則返回-1。

TYPE

最早可用版本1.0.0

返回key儲存的值的型別。型別即為我們在Redis基礎資料結構一文中描述的5中資料型別。

UNLINK

最早可用版本4.0.0

這個命令和DEL類似,會刪除指定的key。所不同的是,此命令的時間複雜度為O(1),它先將key從keyspace中刪除,此時指定的key已經刪除,但是記憶體沒有釋放。所以,這個命令會在另一個執行緒中做釋放記憶體的操作。這一步的操作時間複雜度為O(N)。

WAIT

最早可用版本3.0.0

這個命令會阻塞客戶端,直到前面所有的寫操作都完成並且儲存了指定數量的副本。該命令總會返回副本數量或者超時。