redis的zset解析


最近工作中使用了redis的zset數據結構,爲了能夠熟練清晰的運用這個數據結構,總結如下。

簡介

zset是一個有序集合,每一個成員有一個分數與之對應,成員不可以重複,但是分實時可以重複的,zset會自動用分數對成員進行排序。

zset的常用命令

1.zadd添加語句

zadd key score member
//添加一條key爲rank,score爲1,member爲yc的數據
zadd rank 1 yc

2.查看zset集合的成員個數

zcard key
//查看key爲rank的集合內成員個數
zcard rank

3.查看zset置頂範圍的成員,withscores爲輸出結果帶分數。

zrange key start  end
//獲取從0到10的rank的member
zrange rank 0 10
//獲取rank所有的member
zrange rank 0 -1
//輸出帶分數的結果
zrange rank 0 -1 withscores

4.獲取zset成員的下標位置。

zrank key member
//查看member爲yc的成員在key爲rank集合的位置
zrank rank yc

5.獲取zset集合指定分數之間的成員個數

zcount key start end
//獲取rank分數值在[1,3]之內的值
zcount rank 1 3

6.刪除集合中一個或者多個成員

zrem key member...
//刪除rank中值爲yc和qj的兩個成員
zrem rank yc qj  

7.獲取指定的分數

zscore key member
//獲取rank中tom的分數
zscore rank tom 

8.爲指定成員的分數進行增減操作,負值爲減,正值爲加。zincrby

zincrby key score member
//爲tom的分數值加3
zincrby rank 3 tom

9.根據指定分數的範圍獲取值,zrangebyscore

zrangebyscore key start end
//獲取rank中[0,9]範圍內的對象
zrangebyscore rank 0 9 

10.倒敘,原本默認的zset排序是從小到大按分數排序,有的場景需要用到倒敘 zrerange,zrerangebyscore

zrerange key start  end
zrerangebyscore key start end
//獲取rank中[0,9]範圍內的對象,倒敘
zrerangebyscore rank 0 9 
//獲取從0到10的rank的member,以score倒敘
zreange rank 0 10

11.根據座標,分數範圍刪除數據。zremrangebyscore,zremrangebyrank

zremrangebyscore key start end
zrenrabfebyrank key start end
//刪除key爲rank,分數範圍在[0,8]的成員
zremrangebyscore rank 0 8
//刪除key爲rank,座標範圍在[0,2]的成員
zremrangebyrank rank 0 2 

zset結構分析

zset對象的編碼可以似乎ziplist也可以是skiplist,所以先來理解一下這兩個結構體
實現場景
當數據較少時,sorted set是由一個ziplist來實現的。
當數據多的時候,sorted set是由一個dict + 一個skiplist來實現的。簡單來講,dict用來查詢數據到分數的對應關係,而skiplist用來根據分數查詢數據(可能是範圍查找)。
實現原因
ziplist節省內存,但是增刪改查等操作較慢,而skiplist正好相反,增刪改查非常快,但是相比ziplist會佔用更多內存。redis在保存zset時按如下的規則進行選擇:
當元素個數超過128或最大元素的長度超過64時用skiplist,其他情況下用ziplist,每次對zset進行插入、刪除元素時都會重新判斷是否需要轉換保存格式。

ziplist

簡介
ziplist是一個經過特殊編碼的雙向鏈表,它的設計目標就是爲了提高存儲效率。ziplist可以用於存儲字符串或整數,其中整數是按真正的二進制表示進行編碼的,而不是編碼成字符串序列。它能以O(1)的時間複雜度在表的兩端提供push和pop操作。
ziplist和普通雙向鏈表的區別:
一個普通的雙向鏈表,鏈表中每一項都佔用獨立的一塊內存,各項之間用地址指針(或引用)連接起來。這種方式會帶來大量的內存碎片,而且地址指針也會佔用額外的內存。而ziplist卻是將表中每一項存放在前後連續的地址空間內,一個ziplist整體佔用一大塊內存。它是一個表(list),但其實不是一個鏈表(linked list)。

dict

Redis的字典是用哈希表實現的,一個哈希表裏面有多個哈希表節點,每個節點表示字典的一個鍵值對。
在這裏插入圖片描述

skiplist

簡介
本質是一種查找結構,用於解決算法中的查找問題,根據給定的key快速查找到它所在位置,是對有序鏈表的優化,查找的效率一般爲O(logn)。
例子
1.在普通有序鏈表中查找一個數據,我們要從頭查找,時間複雜度是O(n)
2.在普通鏈表之上,若我們隔一個,生成一個新的鏈表,這樣如果我要查找23流程如下
2.1 23首先和7比較,再和19比較,比它們都大,繼續向後比較。
2.2 但23和26比較的時候,比26要小,因此回到下面的鏈表(原鏈表),與22比較。
2.3 比22要大,沿下面的指針繼續向後和26比較。23比26小,說明待查數據23在原鏈表中不存在,而且它的插入位置應該在22和26之間。
在這裏插入圖片描述由於新增的指針,我們不需要跟鏈表中每個節點進行比較,而是先跳躍着比較,縮小比較範圍,再進行查找增加了查找的效率,在二層之上,我們還可以添加三層,四層,skiplist正式由此啓發而誕生的數據結構。
爲了插入節點方便,skiplist不要求上下相鄰兩層鏈表之間的節點個數有嚴格的對應關係,而是針對每個節點隨機出一個層數,以下是一個skiplist生成的過程。
在這裏插入圖片描述
舉例子,若要在這樣的跳錶查找23,流程如下
在這裏插入圖片描述

參考文章:
http://zhangtielei.com/posts/blog-redis-skiplist.htm
http://zhangtielei.com/posts/blog-redis-ziplist.html
https://blog.csdn.net/QJYWYGQJYWYG/article/details/92847077
https://blog.csdn.net/cxc576502021/article/details/82974940

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章