Redis 常用數據類型 (下)

文章目錄

  • 前言
  • 一 Hash 哈希
    • 1. Hash 相關命令
      • hset 和 hget
      • hexists
      • hdel
      • hkeys
      • hvals
      • hgetall
      • hmget
      • hlen
      • hsetnx
      • hincrby
      • incrbyfloat
    • 2. Hash 命令小結
    • 3. Hash 內部編碼
    • Hash 在緩存中的應用
      • 場景介紹
      • 緩存方式對比
  • 二、List 列表
    • 1. LIST總體介紹
    • 2. List 普通命令
      • lpush
      • lpushx
      • rpush
      • rpushx
      • lrange
      • lpop
      • rpop
      • linsert
      • lindex
      • llen
      • lrem
      • ltrim
      • lset
    • 3. List 阻塞版本命令
      • blpop
      • brpop
    • 4. List 命令小結
    • 5. List 內部編碼
    • List 使用場景
      • 1. 消息隊列
      • 2. 微博timeline
  • 三、Set 集合
    • 1.Set 總體介紹
    • 2. Set 普通命令
      • sadd、 smembers、 sismember
      • scard
      • spop
      • srandmember
      • smove
      • srem
    • 3. 集合間操作
      • sinter
      • sinterstore
      • sunion
      • sunionstore
      • sdiff
      • sdiffstore
    • 4. Set 命令小結
    • 5. Set 內部編碼
    • 6.應用場景
  • 四、Zset 有序集合
    • 1. Zset 總體認識
    • 2. Zset 普通命令
      • zadd
      • zcard
      • zcount
      • zrange
      • zrevrange
      • zrangebyscore
      • zpopmax 和 zpopmin
      • bzpopmax 和 bzpopmin
      • zrank 和 zrevrank
      • zscore
      • zrem
      • zremrangebyrank
      • zremrangebyscore
      • zincrby
      • Zset 集合間操作命令
      • zinterstore
      • zunionstore
    • 4. 命令小結
    • 5. 內部編碼
    • 6. 應用場景---排行榜系統
  • 五、其他類型
  • 六、 補充
    • 漸進式遍歷
    • 數據庫操作
      • select
      • dbsize
      • flushall 和 flushdb

前言

上篇中介紹到了Redis 的 String 類型,本文是下篇,將繼續介紹 Redis 常用數據類型中的 哈希(Hash)** 、列表(List)集合(Set)有序集合(Sorted Set) 和一些其他類型。
Redis常用數據類型(上)

一 Hash 哈希

Redis 本身就是一種 Hash 結構,同時也提供了 Hash 這種數據類型。
下圖闡述了二者的一些差別,同時也體現了 Hash 和 String 在使用時的差別

Redis 本身的鍵值對,官方稱之為 key-value,為了區分,對于 Redis 的 Hash 數據類型,其鍵值對稱為 field-value 。在這種嵌套結構中我們需要注意 value 的具體含義

1. Hash 相關命令

hset 和 hget

這是一對最核心的命令,分別用于設置鍵值對和獲取 field 對應的 value

# 支持一次設置多組值
HSET key field value [field value ...]# 注意這里先指定 key 再指定 field
HGET key field

返回值:hset 返回添加的對數,hget 返回指定 filed 對應的值
示例

127.0.0.1:6379> hset key f1 111
(integer) 1
127.0.0.1:6379> hset key f2 222 f3 333 f4 444
(integer) 3
127.0.0.1:6379> hget key f1
"111"
127.0.0.1:6379> hget key f4
"444"

hexists

判斷是否存在對應字段

hexists key filed

存在則返回 1,不存在返回 0
語法:

# 接著上一個例子,已經存在 f1, f2, f3, f4
127.0.0.1:6379> HEXISTS key f1 
(integer) 1
127.0.0.1:6379> HEXISTS key f2
(integer) 1
127.0.0.1:6379> HEXISTS key f100
(integer) 0

hdel

刪除 hash 中指定的字段,支持刪除多個
返回刪除成功的個數

# 接著上一個例子,已經存在 f1, f2, f3, f4
127.0.0.1:6379> hdel key f1 f100
(integer) 1
127.0.0.1:6379> hget key f1
(nil)

hkeys

獲取指定 key 對應哈希表中 所有 field

hkey key

示例:

127.0.0.1:6379> hkeys key
1) "f2"
2) "f3"
3) "f4"

hkeys 有風險!當 key 對應的hash表數據過多,就會阻塞 redis 服務器

hvals

獲取指定 key 對應 hash 表中 所有 value

hvals key

示例:

127.0.0.1:6379> hvals key
1) "222"
2) "333"
3) "444"

hgetall

獲取指定 key 對應 hash 表中 所有 field-value 對

hgetall key

示例:

127.0.0.1:6379> hgetall key
1) "f2"
2) "222"
3) "f3"
4) "333"
5) "f4"
6) "444"

hmget

一次獲取多個 field 對應的值
返回值:返回對應字段的值或者nill

hmget key field [field ...]

示例:

127.0.0.1:6379> hmget key f1 f2 f3 f4
1) (nil)
2) "222"
3) "333"
4) "444"

在使? HGETALL 時,如果哈希元素個數?較多,會存在阻塞 Redis 的可能。如果開發?員只需要獲取部分 field,可以使? HMGET,如果?定要獲取全部 field,可以嘗試使? HSCAN命令,該命令采?漸進式遍歷哈希類型,HSCAN 會在后續章節介紹。

hlen

獲取 hash 中所有字段的個數

hlen key 

示例:

127.0.0.1:6379> hlen key
(integer) 3

hsetnx

若 field 存在 設置鍵值對,否則 不設置
語法:

hsetnx key field value

返回 1 表示設置成功,返回 0 表示失敗

示例:

127.0.0.1:6379> HSETNX myhash field "Hello"
(integer) 1
127.0.0.1:6379> HSETNX myhash field "Hello"
(integer) 0

hincrby

Hash 中的 value 也可以當成整數

HINCRBY key field increment

對 Hash 中 field 對應的 value 值 加一
返回值:變化后的值,不是整數則報錯

示例:

redis> HSET myhash field 5
(integer) 1
redis> HINCRBY myhash field 1
(integer) 6
redis> HINCRBY myhash field -1
(integer) 5
redis> HINCRBY myhash field -10
(integer) -5

incrbyfloat

HINCRBY 的浮點數版本。
語法:

HINCRBYFLOAT key field increment

示例:

redis> HSET mykey field 10.50
(integer) 1
redis> HINCRBYFLOAT mykey field 0.1
"10.6"
redis> HINCRBYFLOAT mykey field -5
"5.6"
redis> HSET mykey field 5.0e3
(integer) 0
redis> HINCRBYFLOAT mykey field 2.0e2
"5200"

2. Hash 命令小結

命令執行效果時間復雜度
hset key field value設置值O(1)
hget key field獲取值O(1)
hdel key field [field …]刪除 fieldO(k), k 是 field 個數
hlen key計算 field 個數O(1)
hgetall key獲取所有的 field - valueO(k), k 是 field 個數
hmget field [field …]批量獲取 field - value
O(k), k 是 field 個數
hmset field value [field value …]批量獲取 field - valueO(k), k 是 field 個數
hexists key field判斷 field 是否存在O(1)
hkeys key獲取所有的 fieldO(k), k 是 field 個數
hvals key獲取所有的 valueO(k), k 是 field 個數
hsetnx key field value設置值,但必須在 field 不存在時才能設置成功O(1)
hincrby key field n對應 field - value +nO(1)
hincrbyfloat key field n對應 field - value +nO(1)
hstrlen key field計算 value 的字符串長度O(1)

3. Hash 內部編碼

哈希的內部編碼有兩種:

  • ziplist(壓縮列表):當哈希類型元素個數?于 hash-max-ziplist-entries 配置(默認 512 個)、同時所有值都?于 hash-max-ziplist-value 配置(默認 64 字節)時,Redis 會使? ziplist 作為哈希的內部實現,ziplist 使?更加緊湊的結構實現多個元素的連續存儲,所以在節省內存???hashtable 更加優秀。
  • hashtable(哈希表):當哈希類型?法滿? ziplist 的條件時,Redis 會使? hashtable 作為哈希的內部實現,因為此時 ziplist 的讀寫效率會下降,? hashtable 的讀寫時間復雜度為 O(1)。

ziplist 的代價就是訪問速度較慢,所以僅在元素個數少且 value 較短時使用

示例:
(1)元素個數較少時,內部編碼采用 ziplist

127.0.0.1:6379> hmset hashkey f1 v1 f2 v2
OK
127.0.0.1:6379> object encoding hashkey
"ziplist"

(2)當有 value 大于 64 字節時,內部編碼會轉換成 hashtable:

127.0.0.1:6379> hset hashkey f3 "超過64字節 .. 省略"
OK
127.0.0.1:6379> object encoding hashkey
"hashtable

(3)當 field 個數超過 512 時,內部編碼也會轉換為 hashtable:

127.0.0.1:6379> hmset hashkey f1 v1 h2 v2 f3 v3 ... 省略 ... f513 v513
OK
127.0.0.1:6379> object encoding hashkey
"hashtable"

Hash 在緩存中的應用

場景介紹

前面提到 String 也可用作緩存場景中,但是在存儲結構化數據上,使用 Hash 更優優勢
使用關系型數據庫存儲:

使用redis 存儲

  • 哈希類型是稀疏的,?關系型數據庫是完全結構化的,例如哈希類型每個鍵可以有不同的 field,?關系型數據庫?旦添加新的列,所有?都要為其設置值,即便沒有,也會默認設置nil,如下圖所示
  • 關系數據庫可以做復雜的關系查詢,? Redis 去模擬關系型復雜查詢,例如聯表查詢、聚合查詢等基本不可能,維護成本?。

緩存方式對比

緩存方式實現方式示例核心優勢主要不足適用場景
原生字符串類型每個屬性單獨設鍵(如set user:1:name James實現極簡,單個屬性操作靈活鍵數量過多,內存占用大,數據分散無內聚性幾乎不推薦,僅臨時調試場景可能使用
序列化字符串類型(如JSON)整體序列化存儲(如set user:1 '{"name":"James"}'數據內聚性好,整體操作高效,內存利用率高序列化/反序列化有性能開銷,局部操作不靈活以整體讀寫為主的場景(如用戶信息完整展示)
哈希類型集中存儲鍵值對(如hmset user:1 name James age 23兼顧簡單性與靈活性,局部操作高效需控制內部編碼轉換,可能引發內存消耗波動頻繁進行局部屬性讀寫的場景(推薦首選)

2.3.5 緩存方式對比

目前,緩存用戶信息可采用以下三種方式,其實現方法及優缺點分析如下:

  1. 原生字符串類型——以字符串類型存儲,每個屬性對應一個鍵
set user:1:name James
set user:1:age 23
set user:1:city Beijing

優點:實現簡單,對單個屬性的變更操作靈活。
缺點:占用鍵數量過多,內存消耗較大;用戶信息在Redis中存儲分散,缺乏內聚性,實際實用性較低。

  1. 序列化字符串類型(如JSON格式)
set user:1 經過序列化 的用戶對象字符串

優點:適合整體操作的信息場景適配性好,編程實現簡單;若選擇合適的序列化方案,內存使用效率較高。
缺點:存在序列化與反序列化的性能開銷,對單個屬性的操作靈活性差。

  1. 哈希類型
hmset user:1 name James age 23 city Beijing

優點:實現簡單、直觀,靈活性強,尤其適合信息的局部變更或獲取操作。
缺點:需控制哈希在ziplist和hashtable兩種內部編碼間的轉換,可能導致較大的內存消耗。

二、List 列表

1. LIST總體介紹

  • 列表類型用來存儲多個字符串,每個字符串可以稱為列表的一個元素,一個列表最多存儲 232?12^{32}-1232?1 個元素。
  • 在 Redis 中,可以對列表兩端插?(push)和彈出(pop),還可以獲取指定范圍的元素列表、獲取指定索引下標的元素等(參考下圖)
  • 由于列表的兩端插入這種靈活特性,它還可以充當棧和隊列的角色,在實際開發中有很多應用
    列表的插入和彈出

    列表的獲取和刪除

    列表元素特點:
  1. 列表元素的位置確定,支持通過下標直接獲取。例如我們可以通過 lindex key 4 獲取列表的第 4 個元素
  2. 如上圖,刪除第二個元素,后面的三個元素均會左移一位
  3. 元素允許重復

Redis 的列表在功能上可類比 c++ 中的雙端隊列 deque,左右插入都是O(1) 常量級復雜度;隨機訪問的話需要從頭遍歷值訪問的下標,是線性復雜度

2. List 普通命令

lpush

將一個或多個元素從左側放入列表中(頭插)
時間復雜度:O(k)(k 為插入元素個數,一般直接視為O(1))

LPUSH key element [element ...]

返回值:插入后 list 的長度

127.0.0.1:6379> lpush mylist "world"
(integer) 1
127.0.0.1:6379> lpush mylist "hello"
(integer) 2
127.0.0.1:6379> Lrange mylist 0 -1
1) "hello"
2) "world"

lpushx

當 key 存在時,將一個或多個元素從左側放入列表中(頭插),如果 key 不存在直接返回
返回值:插入 list 的長度
時間復雜度:O(k)(k 為插入元素個數,一般直接為O(1))

127.0.0.1:6379> lpush mylist1 world
(integer) 1
127.0.0.1:6379> lpushx mylist1 Hello
(integer) 2
127.0.0.1:6379> lpushx otherlist hello
(integer) 0
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"

rpush

將一個或多個元素從右側放入列表中(尾插)

RPUSH key element [element ...] 

返回值插入后列表的長度:
時間復雜度:O(k) (k 為插入元素個數,一般直接為O(1))

rpushx

在 key 存在時,將?個或者多個元素從右側放?(尾插)到 list 中。
語法:

RPUSHX key element [element ...]

返回值:插入后 list 的長度
時間復雜度:O(N) (N 為插入元素個數,一般插入元素較少,可視為O(1))

示例:

redis> RPUSH mylist "World"
(integer) 1
redis> RPUSHX mylist "Hello"
(integer) 2
redis> RPUSHX otherlist "Hello"
(integer) 0
redis> LRANGE mylist 0 -1
1) "World"
2) "Hello"
redis> LRANGE otherlist 0 -1
(empty array)

lrange

獲取從 start 到 end 區間的所有元素,左閉右閉。
語法:

LRANGE key start stop

最壞時間復雜度:O(N)
返回值:指定區間的元素。
示例:

127.0.0.1:6379> lrange mylist 0 0 
1) "hello"
127.0.0.1:6379> lrange mylist -3 2
2) "hello"
3) "world"
127.0.0.1:6379> lrange mylist -100 100
4) "hello"
5) "world"
127.0.0.1:6379> lrange mylist 4 6
(empty array)

lpop

從 list 左側取出數據(頭刪)
語法:

lop key

返回值:取出的元素或者 nil
時間復雜度:O(1)

示例:

127.0.0.1:6379> rpush mylist one two three four five
(integer) 5
127.0.0.1:6379> lpop mylist
"one"
127.0.0.1:6379> lpop mylist
"two"
127.0.0.1:6379> lpop mylist
"three"
127.0.0.1:6379> lrange mylist 0 -1
1) "four"
2) "five"

rpop

從右側取出數據
語法:

rpop key

返回值:取出的元素或者 nil
時間復雜度: O(1)

示例:

127.0.0.1:6379> rpush mylist one two three four five
(integer) 5
127.0.0.1:6379> rpop mylist
"five"
127.0.0.1:6379> rpop mylist
"four"
127.0.0.1:6379> rpop mylist
"three"

linsert

根據提供的值查找位置,然后插入元素

LINSERT key <BEFORE | AFTER> pivot element

返回值:插?后的 list ?度。
時間復雜度:O(N)

示例:

redis> RPUSH mylist "Hello"
(integer) 1
redis> RPUSH mylist "World"
(integer) 2
redis> LINSERT mylist BEFORE "World" "There"
(integer) 3
redis> LRANGE mylist 0 -1
1) "Hello"
2) "There"
3) "World"

lindex

獲取指定下標 index 位置的下標
語法:

lindex key index

時間復雜度:O(N)
返回值:取出的元素或者nil

示例:

127.0.0.1:6379> rpush mylist one two three four five
(integer) 5
127.0.0.1:6379> lindex mylist 0
"one"
127.0.0.1:6379> lindex mylist 5
(nil)
127.0.0.1:6379> lindex mylist -1
"five"
127.0.0.1:6379> lindex mylist 4
"five"
127.0.0.1:6379> lindex mylist -4
"two"
127.0.0.1:6379> lindex mylist -5
"one"

llen

獲取 list 長度
語法:

llen key

返回值:list 的長度

127.0.0.1:6379> lpush mylist1 "world"
(integer) 1
127.0.0.1:6379> llen mylist1
(integer) 1

lrem

刪除 count 個 element 元素

LREM key count element
  • count > 0: 從左邊開始找 count 個 等于 element 的元素
  • count < 0: 從右邊開始找 ∣count∣|count|count 個 等于 element 的元素
  • count = 0 : 刪除整個 List 中等于 element 的元素
    時間復雜度:O(N)

示例:

  1. 先構造一個列表,內容為 a b a b a b a b
127.0.0.1:6379> rpush mylist a b
(integer) 2
127.0.0.1:6379> rpush mylist a b
(integer) 4
127.0.0.1:6379> rpush mylist a b
(integer) 6
127.0.0.1:6379> rpush mylist a b
(integer) 8
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "a"
4) "b"
5) "a"
6) "b"
7) "a"
8) "b"
  1. 測試lrem 操作:
127.0.0.1:6379> lrem mylist 2 a
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "b"
2) "b"
3) "a"
4) "b"
5) "a"
6) "b"
127.0.0.1:6379> lrem mylist -2 a
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
7) "b"
8) "b"
9) "b"
10) "b"
127.0.0.1:6379> lrem mylist 0 b
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
(empty array)

ltrim

LTRIM key start stop

僅保留 【start, stop】閉區間中的元素,其余直接刪除,注意下標從0開始
返回值:start, stop 區間內的元素
時間復雜度:O(N)

示例:

127.0.0.1:6379> rpush mylist1 a b c d e f g h
(integer) 8
127.0.0.1:6379> ltrim mylist1 2 5
OK
127.0.0.1:6379> lrange mylist1 0 -1
1) "c"
2) "d"
3) "e"
4) "f"

lset

lset key index element

修改 index 位置的元素為 element
時間復雜度:O(N)
返回值:成功返回 OK,下標超出范圍會報錯

1) "c"
2) "d"
3) "e"
4) "f"
127.0.0.1:6379> lset mylist1 2 "hello world"
OK
127.0.0.1:6379> lrange mylist1 0 -1
5) "c"
6) "d"
7) "hello world"
8) "f"
127.0.0.1:6379> lset mylist1 4 "1"
(error) ERR index out of range

3. List 阻塞版本命令

blpop 和 brpop 是 lpop 和 rpop 的阻塞版本:

  • 在列表中有元素的情況下,阻塞和非阻塞表現是一致的。
  • 如果列表中沒有元素,執行阻塞版本命令的客戶端會根據timeout 阻塞一段時間,期間redis 服務器能正常處理其他客戶端的命令
  • 等待過程中,列表中一旦有元素立即返回
  • 若 Redis 中設置了多個鍵,那么就會從左向右進行遍歷,一旦有一個鍵對應的列表中可以彈出元素,命令立即返回

blpop

lpop 的阻塞版本
語法:

blpop key [key ...] timeout

時間復雜度:O(1)
返回值:取出的數據或者nil

brpop

brpop 的 阻塞版本
語法:

brpop key [key ...] timeout

用法與 blpop 一致,此處不再贅述

brpop 和 blpop 適合用于阻塞隊列

4. List 命令小結

操作類型命令時間復雜度
添加rpush key value [value ...]O(k)O(k)O(k)kkk 是元素個數
添加lpush key value [value ...]O(k)O(k)O(k)kkk 是元素個數
添加linsert key before | after pivot valueO(n)O(n)O(n)nnn 是 pivot 距離頭尾的距離
查找lrange key start endO(s+n)O(s+n)O(s+n)sss 是 start 偏移量,nnn 是 start 到 end 的范圍
查找lindex key indexO(n)O(n)O(n)nnn 是索引的偏移量
查找llen keyO(1)O(1)O(1)
刪除lpop keyO(1)O(1)O(1)
刪除rpop keyO(1)O(1)O(1)
刪除lrem key count valueO(k)O(k)O(k)kkk 是列表長度
刪除ltrim key start endO(k)O(k)O(k)kkk 是列表長度
修改lset key index valueO(k)O(k)O(k)kkk 是索引的偏移量
阻塞操作blpop brpopO(1)O(1)O(1)

5. List 內部編碼

對于舊版本 Redis (Redis 3.2 之前):

  • ziplist(壓縮列表):元素個數少時使用。這種結構更為緊湊,但訪問效率較低,所以僅個數少時使用。
  • linkedlist(鏈表):當列表類型?法滿? ziplist 的條件時,Redis 會使? linkedlist 作為列表的內部實現。
    Redis 3.2 之后,采用 quicklist 作為 List 的底部編碼
    quicklist 時 ziplist 和 linkedlist 的結合,也就是 linkedlist 的每個節點是 ziplist 。

在 /etc/redis/redis.conf 文件中,存在一個配置項 list-max-ziplist-size 表示單個壓縮列表允許的最大字節數。

List 使用場景

普通消息隊列

1. 消息隊列

如下圖所示,生產通過 lpush 放入元素,多個消費者通過 brpop 排隊阻塞等待元素。這多個消費者客戶端就直接能保證負載均衡和高可用

分頻道消息隊列
由于 brpop 支持等待多個鍵的特性,我們可以直接基于此實現一個分頻道消息隊列,實現訂閱不同頻道的效果,如下圖:

2. 微博timeline

每個用戶都有自己的 timeline (微博列表),現需要按照分頁來展示文章列表。此時可考慮使用列表,列表順序固定,且支持按照索引獲取元素

  1. 每篇微博使用 hash 結構存儲
hmset mblog:1 title xx timestamp 1476536196 content xxxxx
...
hmset mblog:n title xx timestamp 1476536196 content xxxxx
  1. 向用戶的 timeline 中添加微博,user:uid:mblogs作為鍵
lpush user:1:mblogs mblog:1 mblog:3
...
lpush user:k:mblogs mblog:9
  1. 分頁獲取用戶的 timeline,例如獲取用戶1的前十篇微博
keylist = lrange user:1:mblogs 0 9
for key in keylist {hgetall key
}

這種方案存在兩個問題:

  1. 第 3)步中,每篇微博都會執行一次 hgetall,這需要多次網絡請求。更推薦的做法是通過 pipeline 流水線式 打包命令,批量提交,一頁只請求一次。
  2. 分頁獲取文章是,lrange 在兩端較快,若是在中間獲取較慢,可考慮將列表做拆分

三、Set 集合

1.Set 總體介紹

集合類型也是保存多個字符串類型的元素的,需要注意:

  1. Set 中元素無序
  2. Set 中元素不能重復
  3. 一個集合最多存 232?12^{32}-1232?1 個元素
    Redis 對 Set 提供了增刪查改的基本操作,同時還支持取交集、并集、差集。

2. Set 普通命令

sadd、 smembers、 sismember

  1. sadd : 將一個或多個元素添加到set中。注意,重復的元素無法添加到 set 中
SADD key member [member ...]
  • 時間復雜度:O(1)
  • 返回值:本次成功添加的元素個數
    示例:
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SADD myset "World"
(integer) 0
redis> SMEMBERS myset
1) "Hello"
2) "World"
  1. smembers : 獲取出集合中的所有元素
  • 時間復雜度: O(1)
  • 返回值: 所有元素
    示例:
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SADD myset "World"
(integer) 0
redis> SMEMBERS myset
1) "Hello"
2) "World"
  1. sismember : 判斷一個元素在不在 set 中
SISMEMBER key member
  • 時間復雜度:O(1)
  • 返回值:1表示元素在 set 中,0表示不再

示例:

redis> SADD myset "one"
(integer) 1
redis> SISMEMBER myset "one"
(integer) 1
redis> SISMEMBER myset "two"
(integer) 0

scard

獲取 set 中的元素個數

SCARD key
  • 時間復雜度:O(1)
  • 返回值:元素個數
    示例:
127.0.0.1:6379> sadd myset 1 2 3 4 5
(integer) 5
127.0.0.1:6379> scard myset
(integer) 5

spop

從 set 中隨機刪除并返回一個或多個元素。

spop key [count]
  • 時間復雜度 : O(k) k 是count
  • 返回值:取出的元素
    示例:
127.0.0.1:6379> smembers myset
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> spop myset 3
6) "2"
7) "3"
8) "1"
127.0.0.1:6379> smembers myset
9) "4"
10) "5"
127.0.0.1:6379> spop myset 1
11) "4"

srandmember

隨機取一個或多個元素

SRANDMEMBER key [count]
  1. 當 count 為正數時:
    返回集合中不重復的隨機元素,數量為 count(若集合元素總數小于 count,則返回所有元素)
  2. 當 count 為負數時:
    返回的隨機元素可能重復,數量為 count 的絕對值(即使集合元素總數小于該絕對值,也會返回指定數量的元素,允許重復)
  3. 當 count 未指定時:
    默認返回 1 個隨機元素(不重復)
  • 時間復雜度:O(N) N 為count

smove

將一個元素從 源 set中取出放入目標 set

smove source destination member
  • 時間復雜度:O(1)
  • 1表示移動成功,0表示失敗

如果 destination 集合中有指定元素,則不會認為移動失敗,效果相當于從source中刪除指定元素,當然如果 source中沒有member,則會返回0認為移動失敗

示例:

redis> SADD myset "one"
(integer) 1
redis> SADD myset "two"
(integer) 1
redis> SADD myotherset "three"
(integer) 1
redis> SMOVE myset myotherset "two"
(integer) 1
redis> SMEMBERS myset
1) "one"redis> SMEMBERS myotherset
1) "three"
2) "two

srem

將指定元素刪除

SREM key member [member ...]
  • 時間復雜度 O(N) N為總元素個數
  • 返回值:本次操作刪除的元素個數
    示例:
redis> SADD myset "one"
(integer) 1
redis> SADD myset "two"
(integer) 1
redis> SADD myset "three"
(integer) 1
redis> SREM myset "one"
(integer) 1
redis> SREM myset "four"
(integer) 0
redis> SMEMBERS myset
1) "three"
2) "two"

3. 集合間操作

交集、并集、差集

sinter

獲取指定集合的交集

SINTER key [key ...]
  • 時間復雜度:O(N * M), N 是最?的集合元素個數. M 是最?的集合元素個數.
  • 返回值:交集的元素
127.0.0.1:6379> sadd key 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd key2 3 4 5 6
(integer) 4
127.0.0.1:6379> sinter key key2
1) "3"
2) "4"

sinterstore

求交集,并把交集元素放入一個新創建的 集合中

SINTERSTORE destination key [key ...]
  • 時間復雜度:O(N * M), N 是最?的集合元素個數. M 是最?的集合元素個數.
  • 返回值:交集的元素個數

示例:

127.0.0.1:6379> sadd key 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd key2 3 4 5 6
(integer) 4
127.0.0.1:6379> SINTERSTORE inter_set key key2
(integer) 2
127.0.0.1:6379> SMEMBERS inter_set
1) "3"
2) "4"

sunion

獲取指定集合的并集

SUNION key [key ...]
  • 時間復雜度:O(N ), 總元素個數.
  • 返回值:并集的元素
    示例:
127.0.0.1:6379> sunion key key2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"

sunionstore

求并集,并把并集元素放入一個新創建的 集合中

SINTERSTORE destination key [key ...]
  • 時間復雜度:O(N),總元素個數
  • 返回值:并集的元素個數
127.0.0.1:6379> sunionstore union_key key key2
(integer) 6
127.0.0.1:6379> SMEMBERS union_key
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"

sdiff

獲取給定 set 的元素個數
語法:

sdiff key [key ...]

時間復雜度:O(N),N給定的集合的總的元素個數
返回值:差集的元素

127.0.0.1:6379> sadd key2 3 4 5
(integer) 3
127.0.0.1:6379> sdiff key1 key2
1) "1"
2) "2"
127.0.0.1:6379> sdiff key2 key1
3) "5"

sdiffstore

求差集,并把差集元素放入一個新創建的 集合中

SDIFFSTORE destination key [key ...]
  • O(N), N 給定的所有集合的總的元素個數
  • 返回值:差集的元素個數。

4. Set 命令小結

以下是轉換后的 Markdown 格式:

命令時間復雜度
sadd key element [element …]O(k),k 是元素個數
srem key element [element …]O(k),k 是元素個數
scard keyO(1)
sismember key elementO(1)
srandmember key [count]O(n),n 是 count
spop key [count]O(n), n 是 count
smembers keyO(k),k 是元素個數
sinter key [key …] sitnerstoreO(m * k),k 是幾個集合中元素最小的個數,m 是鍵個數
sunion key [key …] sunionstoreO(k),k 是多個集合的元素個數總和
sdiff key [key …] sdiffstoreO(k),k 是多個集合的元素個數總和

5. Set 內部編碼

集合的編碼有兩種:

  • intset (整數集合):當集合中的元素都是整數并且元素的個數?于 set-max-intset-entries 配置(默認 512 個)時,Redis 會選? intset 來作為集合的內部實現,從?減少內存的占用。
  • hashtable(哈希表):當集合類型?法滿? intset 的條件時,Redis 會使? hashtable 作為集合的內部實現。

6.應用場景

用戶興趣標簽
場景:給用戶打興趣標簽(如 “籃球”“音樂”“閱讀”),用于個性化推薦。
實現:

  • 用 Set 存儲用戶的興趣標簽:SADD user:10086:interests 籃球 音樂
    推薦邏輯:
  • 計算用戶興趣交集:SINTER user:10086:interests user:10010:interests(找到與用戶 10086 興趣相似的用戶 10010)
  • 還可以通過交集計算用戶群體的共同標簽
  • 基于標簽推送內容:SUNION tag:籃球 tag:音樂(獲取用戶可能感興趣的內容 ID)

四、Zset 有序集合

1. Zset 總體認識

有序集合保留了 Set 的元素不能重復特性,并在此基礎上給每個元素引入了 分數(score),Zset 會基于分數對元素進行升序排序,這就是 Zset 的有序特性。
Zset 提供了獲取指定分數和元素范圍查找、計算成員排名等功能,合理利用 Zset 可以幫助我們在實際開發中解決很多問題

Zset 元素不能重復,但不同元素的分數可以一樣

關于有序概念在不同上下文中的理解

數據結構是否允許重復元素是否有序有序依據應用場景
列表索引下標時間軸、消息隊列等
集合標簽、社交等
有序集合分數排行榜系統、社交等

2. Zset 普通命令

zadd

  • 添加或者更新指定的元素以及關聯的分數到 zset 中,可添加多對。
  • 分數應該符合 double 類型,+inf/-inf 作為正負極限也是合法的。
    語法:
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]

選項介紹:

  • XX 表示僅在member 存在的情況下更新元素的分數
  • NX 表示僅在 member 不存在的情況下添加新元素和分數
  • CH:默認情況下,ZADD 返回的是本次添加的元素個數,但指定這個選項之后,就會還會包含本次更新的元素的個數。
  • INCR:此時命令類似 ZINCRBY 的效果,將元素的分數加上指定的分數。此時只能指定?個元素和分數。
  • LT : less than 的縮寫,表示僅在分數比原來小的時候更新分數
  • GT : greater than 的縮寫,表示僅在分數比原來大的時候更新分數

時間復雜度:O(log(N)) N 是 Zset 的總元素個數
返回值:本次添加成功的元素個數
示例:

  1. 不加選項(需要注意的就是每一對元素中,分數在前,名稱在后)
127.0.0.1:6379> zadd my_zset 99 Tom 99 Jerry 97 David 95 Tim
(integer) 4
127.0.0.1:6379> zrange 0 -1
1) "Tim"
2) "David"
3) "Jerry"
4) "Tom"127.0.0.1:6379> zrange my_zset 0 -1 withscores
1) "Tim"
2) "95"
3) "David"
4) "97"
5) "Jerry"
6) "99"
7) "Tom"
8) "99"127.0.0.1:6379> zadd my_zset 90 Tom
(integer) 0
127.0.0.1:6379> zrange my_zset 0 -1
1) "Tom"
2) "Tim"
3) "David"
4) "Jerry"
  1. XX 和 NX
127.0.0.1:6379> zadd my_zset NX 0 Jerry 
(integer) 0
127.0.0.1:6379> zrange my_zset 0 -1 withscores
1) "Tom"
2) "90"
3) "Tim"
4) "95"
5) "David"
6) "97"
7) "Jerry"
8) "99"
127.0.0.1:6379> zadd my_zset XX 0 Jerry 
(integer) 0127.0.0.1:6379> zrange my_zset 0 -1 withscores
1) "Jerry"
2) "0"
3) "Tom"
4) "90"
5) "Tim"
6) "95"
7) "David"
8) "97"127.0.0.1:6379> zadd my_zset XX 100 zhangsan 
(integer) 0
127.0.0.1:6379> zrange my_zset 0 -1 withscores
1) "Jerry"
2) "0"
3) "Tom"
4) "90"
5) "Tim"
6) "95"
7) "David"
8) "97"127.0.0.1:6379> zadd my_zset NX 100 zhangsan 
(integer) 1
127.0.0.1:6379> zrange my_zset 0 -1 withscores1) "Jerry"2) "0"3) "Tom"4) "90"5) "Tim"6) "95"7) "David"8) "97"9) "zhangsan"
10) "100"
  1. CH選項
127.0.0.1:6379> zadd my_zset 100 Tom
(integer) 0
127.0.0.1:6379> zadd my_zset CH 100 Jerry
(integer) 1
  1. INCR
127.0.0.1:6379> zrange my_zset 0 -1 withscores1) "David"2) "97"3) "Jerry"4) "100"5) "Tim"6) "100"7) "Tom"8) "100"9) "zhangsan"
10) "100"
127.0.0.1:6379> zadd my_zset incr 100 Tim
"200"
127.0.0.1:6379> zrange my_zset 0 -1 withscores11) "David"12) "97"13) "Jerry"14) "100"15) "Tom"16) "100"17) "zhangsan"18) "100"19) "Tim"
20) "200"

zcard

獲取 zset 中的元素個數

ZCARD key
  • 時間復雜度:O(1)
  • 返回值:zset 內的元素個數。
127.0.0.1:6379> zrange my_zset 0 -1 withscores1) "David"2) "97"3) "Jerry"4) "100"5) "Tim"6) "100"7) "Tom"8) "100"9) "zhangsan"
10) "100"
127.0.0.1:6379> zcard my_zset
(integer) 5

zcount

返回分數在 min 和 max 之間的元素個數,默認情況下,min 和 max 都是包含的。通過 ( 可以改為開區間

ZCOUNT key min max
  • 時間復雜度:O(log(N))
  • 返回值:滿足條件的元素列表個數

示例:

127.0.0.1:6379> zrange my_zset 0 -1 withscores1) "David"2) "97"3) "Jerry"4) "100"5) "Tom"6) "100"7) "zhangsan"8) "100"9) "Tim"
10) "200"
127.0.0.1:6379> zcount my_zset 100 200
(integer) 4
127.0.0.1:6379> zcount my_zset (100 200
(integer) 1
127.0.0.1:6379> zcount my_zset (100 (200
(integer) 0

zrange

返回指定區間?的元素,分數按照升序。帶上 WITHSCORES 可以把分數也返回。

ZRANGE key start stop [WITHSCORES]

此處的 [start, stop] 為下標構成的閉區間. 從 0 開始, ?持負數.

時間復雜度:O(log(N)+M N 是 Zset 總元素個數,M是區間內元素個數
返回值:區間內的元素列表。

zrevrange

返回指定區間?的元素,分數按照降序。帶上 WITHSCORES 可以把分數也返回。

ZREVRANGE key start stop [WITHSCORES]

備注:這個命令在 6.2.0 之后廢棄,并且功能合并到 ZRANGE 中。本博客僅針對Redis 6.0 所以不做過多討論

時間復雜度:O(log(N)+M)
返回值:區間內的元素列表。

zrangebyscore

返回分數在 min 和 max 之間的元素,默認情況下,min 和 max 都是包含的,可以通過 ( 來改成開區間。

備注:這個命令在 6.2.0 之后廢棄,并且功能合并到 ZRANGE 中。

語法:

ZRANGEBYSCORE key min max [WITHSCORES]

時間復雜度:O(log(N)+M)
返回值:區間內的元素列表。

示例:

127.0.0.1:6379> zrangebyscore my_zset 0 100  withscores
1) "David"
2) "97"
3) "Jerry"
4) "100"
5) "Tom"
6) "100"
7) "zhangsan"
8) "100"

zpopmax 和 zpopmin

  1. zpopmax : 刪除并返回分數最?的 count 個元素。
ZPOPMAX key [count]
  • 時間復雜度:O(log(N) * M)
  • 返回值:分數和元素列表。

優先刪除字典序更低的元素

示例:

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZPOPMAX myzset
1) "three"
  1. zpopmin :刪除并返回分數最低的 count 個元素。
ZPOPMIN key [count]
  • 時間復雜度:O(log(N) * M)
  • 返回值:分數和元素列表。

分數相同,優先刪除字典序低的

redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZPOPMIN myzset
1) "one"
2) "1"

bzpopmax 和 bzpopmin

這是 zpopmax 和 zpopmin 的阻塞版本((僅支持彈出一個元素,可阻塞等待多個 key ),可用于實現阻塞優先級隊列。

  1. BZPOPMAX
1 BZPOPMAX key [key ...] timeout
  • 時間復雜度:O(log(N))
  • 返回值:元素列表。
    ?例:
redis> DEL zset1 zset2
(integer) 0
redis> ZADD zset1 0 a 1 b 2 c
(integer) 3
redis> BZPOPMAX zset1 zset2 0
1) "zset1"
2) "c"
3) "2"
  1. ZPOPMIN
BZPOPMIN key [key ...] timeout
  • 時間復雜度:O(log(N))
  • 返回值:元素列表。
    示例:
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZPOPMIN myzset
1) "one"
2) "1

zrank 和 zrevrank

  1. zrank : 返回指定元素按照升序的排名
ZRANK key member
  • 時間復雜度:O(log(N))
  • 返回值:排名。
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZRANK myzset "three"
(integer) 2
redis> ZRANK myzset "four"
(nil)
  1. zrevrank:返回指定元素的排名,降序。
zrevrank key member
  • 時間復雜度:O(log(N))
  • 返回值:排名。
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREVRANK myzset "one"
(integer) 2
redis> ZREVRANK myzset "four"
(nil)

zscore

返回指定元素的分數

ZSCORE key member
  • 時間復雜度:O(1),redis對此做了特殊優化
  • 返回值:分數。
    示例:
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZSCORE myzset "one"
"1"

zrem

刪除指定的元素

ZREM key member [member ...]
  • 時間復雜度:O(M * log(N)) (M 是刪除的元素個數)
  • 返回值:本次操作刪除的元素個數。
    示例:
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREM myzset "two"
(integer) 1
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "three"
4) "3"

zremrangebyrank

按照升序刪除指定范圍的元素,閉區間

ZREMRANGEBYRANK key start stop
  • 時間復雜度:O(log(N)+M) M 是被刪除的元素個數
  • 返回值:本次操作刪除的元素個數。
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREMRANGEBYRANK myzset 0 1
(integer) 2
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "three"
2) "3"

zremrangebyscore

按照分數刪除指定范圍的元素,左閉右閉。

ZREMRANGEBYSCORE key min max
  • 時間復雜度:O(log(N)+M)
  • 返回值:本次操作刪除的元素個數。
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREMRANGEBYSCORE myzset -inf (2
(integer) 1
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "two"
2) "2"
3) "three"
4) "3"

zincrby

為指定的元素的關聯分數加上指定的分數值。

ZINCRBY key increment member
  • 時間復雜度:O(log(N))
  • 返回值:增加后元素的分數

Zset 集合間操作命令

交集

zinterstore

求出給定有序集合中元素的交集并保存進?標有序集合中,在合并過程中以元素為單位進?合并,元素對應的分數按照不同的聚合?式和權重得到新的分數。

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>]

選項介紹:

  • numkeys : 必須指定要合并的 key 的數量
  • WEIGHTS:可選,為待合并的key 分配權重
  • AGGREGATE :可選 sum | min | max , 分別是按權重求和,乘以權重后取最小值,乘以權重后取最大值。
    時間復雜度:O(N?K)+O(M?log(M))O(N*K)+O(M*log(M))O(N?K)+O(M?log(M)) N 是輸?的有序集合中, 最小的有序集合的元素個數; K 是輸入了幾個有序集合; M 是最終結果的有序集合的元素個數
    返回值:最終結果的有序集合的元素個數

示例:

zunionstore

求出給定有序集合中元素的并集并保存進?標有序集合中,在合并過程中以元素為單位進?合并,元素對應的分數按照不同的聚合?式和權重得到新的分數。

ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight[weight ...]] [AGGREGATE <SUM | MIN | MAX>]
  • 時間復雜度:O(N)+O(M?log(M))O(N)+O(M*log(M))O(N)+O(M?log(M)) N 是輸?的有序集合總的元素個數; M 是最終結果的有序集合的元素個數.
  • 返回值:?標集合中的元素個數
    選項和 zinterstore 一樣
    示例:

4. 命令小結

命令時間復雜度
zadd key score member [score member ...]O(k?log?(n))O(k \cdot \log(n))O(k?log(n))kkk 是添加成員的個數,nnn 是當前有序集合的元素個數
zcard keyO(1)O(1)O(1)
zscore key memberO(1)O(1)O(1)
zrank key member
zrevrank key member
O(log?(n))O(\log(n))O(log(n))nnn 是當前有序集合的元素個數
zrem key member [member ...]O(k?log?(n))O(k \cdot \log(n))O(k?log(n))kkk 是刪除成員的個數,nnn 是當前有序集合的元素個數
zincrby key increment memberO(log?(n))O(\log(n))O(log(n))nnn 是當前有序集合的元素個數
zrange key start end [withscores]
zrevrange key start end [withscores]
O(k+log?(n))O(k + \log(n))O(k+log(n))kkk 是獲取成員的個數,nnn 是當前有序集合的元素個數
zrangebyscore key min max [withscores]
zrevrangebyscore key max min [withscores]
O(k+log?(n))O(k + \log(n))O(k+log(n))kkk 是獲取成員的個數,nnn 是當前有序集合的元素個數
zcount key min maxO(log?(n))O(\log(n))O(log(n))nnn 是當前有序集合的元素個數
zremrangebyrank key start endO(k+log?(n))O(k + \log(n))O(k+log(n))kkk 是獲取成員的個數,nnn 是當前有序集合的元素個數
zremrangebyscore key min maxO(k+log?(n))O(k + \log(n))O(k+log(n))kkk 是獲取成員的個數,nnn 是當前有序集合的元素個數
zinterstore destination numkeys key [key ...]O(n?k)+O(m?log?(m))O(n \cdot k) + O(m \cdot \log(m))O(n?k)+O(m?log(m))nnn 是輸入的集合最小的元素個數,kkk 是集合個數,mmm 是目標集合元素個數
zunionstore destination numkeys key [key ...]O(n)+O(m?log?(m))O(n) + O(m \cdot \log(m))O(n)+O(m?log(m))nnn 是輸入集合總元素個數,mmm 是目標集合元素個數

5. 內部編碼

有序集合類型的內部編碼有兩種:

  • ziplist(壓縮列表):當有序集合的元素個數?于 zset-max-ziplist-entries 配置(默認 128 個),同時每個元素的值都?于 zset-max-ziplist-value 配置(默認 64 字節)時,Redis 會? ziplist 來作為有序集合的內部實現,ziplist 可以有效減少內存的使?。
  • skiplist(跳表):當 ziplist 條件不滿?時,有序集合會使? skiplist 作為內部實現,因為此時ziplist 的操作效率會下降。

關于跳表將在后續介紹

6. 應用場景—排行榜系統

在使用 Redis 的有序集合(Zset)維護每天的熱榜(以點贊數為維度)這一場景中,Zset 的特性使其成為一個非常合適的選擇,以下是具體的介紹:

  1. 初始化熱榜:每天開始時,可以創建一個新的 Zset 來存儲當天的熱榜數據。例如,使用鍵名 hot_list:2024-10-01 來表示 2024年10月1日的熱榜,使用 ZADD 命令向其中添加帖子的 ID 作為成員,初始點贊數(假設為0)作為分數。

    ZADD hot_list:2024-10-01 0 post_1
    ZADD hot_list:2024-10-01 0 post_2
    
  2. 更新點贊數:當有用戶對帖子進行點贊操作時,通過 ZINCRBY 命令增加對應帖子在 Zset 中的點贊數(分數)。

    ZINCRBY hot_list:2024-10-01 1 post_1
    
  3. 獲取熱榜數據:要獲取當天點贊數排名前10的帖子,可以使用 ZREVRANGE 命令(因為點贊數越高越熱門,所以使用反向排序獲取高分元素)。

    ZREVRANGE hot_list:2024-10-01 0 9 WITHSCORES
    

    其中 WITHSCORES 參數用于在返回成員的同時返回其對應的分數(點贊數),方便展示。

  4. 獲取特定帖子的排名:如果想知道某個帖子在熱榜中的排名,可以使用 ZREVRANK 命令。

    ZREVRANK hot_list:2024-10-01 post_1
    

    該命令會返回帖子 post_1 在熱榜中的排名(從0開始計數)。

五、其他類型

Redis 數據類型
Redis 還提供了其他的一些數據類型,雖然這些類型使用率不高,但在特定場景下使用,還是方便且高效的。

  • Streams : 類似于消息隊列(阻塞隊列),支持高效的消息發布、訂閱等功能
  • Geospatial : 用于存儲地理坐標的(經緯度)。支持用戶在不同坐標減進行距離查詢等操作
  • Hyperloglog : 以極低的空間代價,估算大集合元素的個數(單個 Hyperloglog 12 KB)
  • Bitset :位圖,用一個bit表示對應位的數字是否存在
  • BitFields :位域類型,位域可以指定每一個元素所占比特位,從而更方便的進行位操作。(類似 c 的位段)

六、 補充

漸進式遍歷

keys * 在生產環境中很危險。
通過漸進式遍歷,就可以做到,既能夠獲取所有的key,同時又不會卡死服務器

以漸進式的方式進行鍵的遍歷

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
  • 時間復雜度 O(1)
  • 下一次scan的的光標(cursor)以及本次得到的鍵
    選項:
  • pattern 同 keys 命令
  • count :限制本次遍歷能獲取到多少元素,默認為 10 。count不是精確值,實際返回的個數可能略有出入
  • type : 僅返回 value 是對應類型的key

count 并非下標,實際返回的數字我們是無法預測的,我們只知道 0 表示開始以及接著上一次scan 命令返回的count 繼續遍歷

示例:

127.0.0.1:6379> mset k1 1 k2 2 k3 3 k4 4 k5 5 k6 6 k7 7 k8 8 k9 9 k0 0 
OK
127.0.0.1:6379> scan 0
1) "15"
2)  1) "k7"2) "k8"3) "k1"4) "k5"5) "k2"6) "k0"7) "k3"8) "k9"9) "k4"3) "k6"127.0.0.1:6379> scan 15
1) "0"
2) (empty array)127.0.0.1:6379> scan 0 count 5
1) "14"
2) 1) "k7"3) "k8"4) "k1"5) "k5"6) "k2"127.0.0.1:6379> scan 14 count 5
1) "15"
2) 1) "k0"3) "k3"4) "k9"5) "k4"6) "k6"127.0.0.1:6379> scan 15 count 5
1) "0"
2) (empty array)

除了 scan 以外,Redis ?向哈希類型、集合類型、有序集合類型分別提供了 hscan、sscan、zscan 命令,它們的?法和 scan 基本類似,感興趣的讀者可以??做擴展學習。

漸進性遍歷 scan 雖然解決了阻塞的問題,但如果在遍歷期間鍵有所變化(增加、修改、刪除),可能導致遍歷時鍵的重復遍歷或者遺漏,這點務必在實際開發中考慮。

數據庫操作

MySQL 中有 database 的概念,一個 MySQL服務器可以有多個 database

Redis 不能創建數據庫,而是本身就提供了16個數據庫(0 - 15),各個數據庫相互獨立。默認操作 0 號數據庫

Redis提供了數據庫相關的命令:dbsize、select、flushdb、flushall 命令。

select

切換數據庫

select dbIndex

各個數據庫之間相互獨立,dbIndex 取 0-15
示例:

127.0.0.1:6379> scan 0
1) "15"
2)  1) "k7"2) "k8"3) "k1"4) "k5"5) "k2"6) "k0"7) "k3"8) "k9"9) "k4"3) "k6"127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> scan 0
1) "0"
2) (empty array)

? Redis 中雖然?持多數據庫,但隨著版本的升級,其實不是特別建議使?多數據庫特性。如果真的需要完全隔離的兩套鍵值對,更好的做法是維護多個 Redis 實例,?不是在?個Redis 實例中維護多數據庫。這是因為本? Redis 并沒有為多數據庫提供太多的特性,其次?論是否有多個數據庫,Redis 都是使?單線程模型,所以彼此之間還是需要排隊等待命令的執?。同時多數據庫還會讓開發、調試和運維?作變得復雜。所以實踐中,始終使?數據庫 0 其實是?個很好的選擇。

dbsize

返回當前數據庫鍵的個數

127.0.0.1:6379> dbsize 
(integer) 10
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> dbsize 
(integer) 0

flushall 和 flushdb

  • flushdb : 清空當前數據庫
  • flushall : 清空所有數據庫

? 永遠不要在線上環境執?清除數據的操作

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917946.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917946.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917946.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java Lambda表達式:簡潔高效的函數式編程

1 lambda表達式Lambda 表達式本質是一個匿名函數&#xff0c;用于把函數作為參數&#xff0c;傳入方法中&#xff0c;實現函數式編程風格。使用Lambda 表達式可以使代碼變的更加簡潔緊湊。語法格式&#xff1a;(parameters)-> expression 或 (parameters)->{ statements…

python中的集合

目錄 初識集合 集合的含義 集合的作用 集合的使用場景 集合的定義 集合的常用操作 元素的增加 函數add() 元素的刪除 函數remove() 函數clear() 函數pop() 集合的遍歷 for循環 while循環 初識集合 集合的含義 在pyrhon中&#xff0c;集合是一種內置的數據結構…

如何將普通HTTP API接口改造為MCP服務器

在現代微服務架構中&#xff0c;MCP&#xff08;Mesh Configuration Protocol&#xff09; 作為高效配置分發協議&#xff0c;正逐漸替代傳統HTTP API。本文將手把手教你如何將普通HTTP API升級為高性能MCP服務器。 為什么需要MCP&#xff1f; 傳統HTTP API在配置分發場景存在…

數據結構第8問:什么是樹?

樹 【本節僅描述樹的定義、術語以及相關性質】 定義 樹是由若干個結點組成的有限集合。具有如下特征&#xff1a; 有且僅有一個根結點&#xff1b;除根結點外&#xff0c;每個其它結點有且僅有一個直接的父結點&#xff1b;除根結點外&#xff0c;每個結點可以有零個或者多個子…

PyTorch RNN 名字分類器

PyTorch RNN 名字分類器詳解 使用PyTorch實現的字符級RNN&#xff08;循環神經網絡&#xff09;項目&#xff0c;用于根據人名預測其所屬的語言/國家。該模型通過學習不同語言名字的字符模式&#xff0c;夠識別名字的語言起源。 環境設置 import torch import string import un…

面向對象之類方法,成員變量和局部變量

1.類的方法必須包含幾個部分&#xff1f;2.成員變量和局部變量類的方法必須包含哪幾個部分&#xff1f;.方法名&#xff1a;用于標識方法的名稱&#xff0c;遵循標識符命名規則&#xff0c;通常采用駝峰命名法。返回值類型&#xff1a;指定方法返回的數據類型。如果方法不返回任…

古法筆記 | 通過查表進行ASCII字符編碼轉換

ASCII字符集是比較早期的一種字符編碼&#xff0c;只能表示英文字符&#xff0c;最多能表示128個字符。 字符集規定了每個字符和二進制數之間的對應關系&#xff0c;可以通過查表完成二進制數到字符的轉換ASCII字符占用的存儲空間是定長的1字節 ASCII字符的官方碼點表見下圖&…

Linux C實現單生產者多消費者環形緩沖區

使用C11里的原子變量實現&#xff0c;沒有用互斥鎖&#xff0c;效率更高。ring_buffer.h:/*** file ring_buffer.h* author tl* brief 單生產者多消費者環形緩沖區&#xff0c;每條數據被所有消費者讀后才釋放。讀線程安全&#xff0c;寫僅單線程。* version* date 2025-08-06*…

復雜場景識別率↑31%!陌訊多模態融合算法在智慧環衛的實戰解析

摘要&#xff1a;針對邊緣計算優化的垃圾堆放識別場景&#xff0c;本文解析了基于動態決策機制的視覺算法如何提升復雜環境的魯棒性。實測數據顯示在遮擋/光照干擾下&#xff0c;mAP0.5較基線提升28.3%&#xff0c;誤報率降低至行業1/5水平。一、行業痛點&#xff1a;智慧環衛的…

MyBatis-Plus Service 接口:如何在 MyBatis-Plus 中實現業務邏輯層??

全文目錄&#xff1a;開篇語前言1. MyBatis-Plus 的 IService 接口1.1 基本使用示例&#xff1a;創建實體類 User 和 UserService1.2 創建 IService 接口1.3 創建 ServiceImpl 類1.4 典型的數據庫操作方法1.4.1 save()&#xff1a;保存數據1.4.2 remove()&#xff1a;刪除數據1…

[激光原理與應用-168]:光源 - 常見光源的分類、特性及應用場景的詳細解析,涵蓋技術原理、優缺點及典型應用領域

一、半導體光源1. LED光源&#xff08;發光二極管&#xff09;原理&#xff1a;通過半導體PN結的電子-空穴復合發光&#xff0c;波長由材料帶隙決定&#xff08;如GaN發藍光、AlGaInP發紅光&#xff09;。特性&#xff1a;優點&#xff1a;壽命長&#xff08;>5萬小時&#…

Metronic v.7.1.7企業級Web應用前端框架全攻略

本文還有配套的精品資源&#xff0c;點擊獲取 簡介&#xff1a;Metronic是一款專注于構建響應式、高性能企業級Web應用的前端開發框架。最新版本v.7.1.7引入了多種功能和優化&#xff0c;以增強開發效率和用戶體驗。詳細介紹了其核心特性&#xff0c;包括響應式設計、多種模…

鴻蒙開發--Notification Kit(用戶通知服務)

通知是手機系統中很重要的信息展示方式&#xff0c;通知不僅可以展示文字&#xff0c;也可以展示圖片&#xff0c;甚至可以將組件加到通知中&#xff0c;只要用戶不清空&#xff0c;通知的信息可以永久保留在狀態欄上通知的介紹 通知 Notification通知&#xff0c;即在一個應用…

鴻蒙 - 分享功能

文章目錄一、背景二、app發起分享1. 通過分享面板進行分享2. 使用其他應用打開二、處理分享的內容1. module.json5 配置可接收分享2. 解析分享的數據一、背景 在App開發中&#xff0c;分享是常用功能&#xff0c;這里介紹鴻蒙開發中&#xff0c;其他應用分享到自己的app中&…

【Agent 系統設計】基于大語言模型的智能Agent系統

一篇阿里博文引發的思考和探索。基于大語言模型的智能Agent系統 1. 系統核心思想 核心思想是構建一個以大語言模型&#xff08;LLM&#xff09;為“大腦”的智能代理&#xff08;Agent&#xff09;&#xff0c;旨在解決將人類的自然語言指令高效、準確地轉化為機器可執行的自動…

企業級Web框架性能對決:Spring Boot、Django、Node.js與ASP.NET深度測評

企業級Web應用的開發效率與運行性能直接關系到業務的成敗。本文通過構建標準化的待辦事項&#xff08;Todo&#xff09;應用&#xff0c;對四大主流框架——Spring Boot、Django、Node.js和ASP.NET展開全面的性能較量。我們將從底層架構特性出發&#xff0c;結合實測數據與數據…

為什么 `source ~/.bashrc` 在 systemd 或 crontab 中不生效

摘要&#xff1a;你是否遇到過這樣的問題&#xff1a;在終端里運行腳本能正常工作&#xff0c;但用 systemd 或 crontab 自動啟動時卻報錯“命令找不到”、“模塊導入失敗”&#xff1f; 本文將揭示一個深藏在 ~/.bashrc 中的“陷阱”&#xff1a;非交互式 shell 會直接退出&am…

Linux 磁盤中的文件

1.磁盤結構 Linux中的文件加載到內存上之前是放到哪的&#xff1f; 放在磁盤上的文件——>訪問文件&#xff0c;打開它——>找到這個文件——>路徑 但文件是怎樣存儲在磁盤上的 1.1物理結構磁盤可以理解為上百億個小磁鐵&#xff08;如N為1&#xff0c;S為0&#xff0…

【方法】Git本地倉庫的文件夾不顯示紅色感嘆號、綠色對號等圖標

文章目錄前言開始操作winr&#xff0c;輸入regedit&#xff0c;打開注冊表重啟資源管理器前言 這個綠色對號圖標表示本地倉庫和遠程的GitHub倉庫內容保持一致&#xff0c;紅色則是相反咯&#xff0c;給你們瞅一下。 首先這兩個東西你一定要安裝配置好了&#xff0c;安裝順序不…

量化交易與主觀交易:哪種方式更勝一籌?

文章概要 在投資的世界里&#xff0c;量化交易和主觀交易如同冰與火&#xff0c;各自擁有獨特的優勢與挑戰。作為一名投資者&#xff0c;了解這兩種交易方式的差異和各自的優缺點至關重要。本文將從決策依據、執行方式、風險管理等方面深入探討量化交易的精確性與主觀交易的靈活…