1. 程式人生 > 其它 >有序集合物件 - 《Redis設計與實現》讀書筆記

有序集合物件 - 《Redis設計與實現》讀書筆記

有序集合物件的編碼可以是ziplist或者skiplist

  1. ziplist編碼的有序集合物件使用壓縮列表作為底層實現

每個集合元素使用兩個緊挨在一起的壓縮列表節點來儲存
第一個節點儲存元素的成員,第二個節點儲存元素的分值
壓縮列表內的集合元素按分值從小到大進行排序
分值較小的元素被放置在靠近表頭的方向,分值較大的元素被放置在靠近表尾的方向

  1. skiplist編碼的有序集合物件使用zset結構作為底層實現
// zset結構
typedef struct zset {
    // 字典: 建立一個從成員到分值的對映,憑此用O(1)複雜度查詢給定成員的分值
    // 字典中的每個鍵值對儲存了一個集合元素: 字典的鍵儲存元素的成員,字典的值儲存元素的分值
    dict *dict;
    // 跳躍表: 按分值從小到大儲存集合元素,憑此對有序集合進行範圍型操作
    // 每個跳躍節點都儲存一個集合元素: 跳躍節點的ele屬性儲存了元素的成員,跳躍節點的score屬性儲存了元素的分值
    zskiplist *zsl;
} zset;

有序集合需要同時使用跳躍表和字典來實現的原因:

  1. 若只使用字典來實現有序集合,由於字典以無序的方式儲存集合元素,每次在執行範圍型操作需要對所有元素進行排序,這一過程至少O(NlogN)時間複雜度以及額外的O(N)記憶體空間
  2. 若只使用跳躍表來實現有序集合,根據成員查詢分值這一操作的複雜度將從O(1)上升為O(logN)
    綜上所述,無論單獨使用字典還是跳躍表,在效能上對比同時使用字典和跳躍表都有所降低,所以Redis選擇了同時使用字典和跳躍表兩種資料結構實現有序集合

注意: 字典和跳躍表會共享元素的成員和分值,並不會造成資料容與,也不會造成記憶體浪費

編碼轉換

當有序集合物件可以【同時滿足】以下條件時,有序集合物件的編碼使用ziplist,否則使用skiplist編碼,

  1. 有序集合物件儲存的元素數量小於128個
  2. 有序集合物件儲存的所有元素成員的長度都小於64位元組

編碼的轉換兩個條件的上限值可通過配置檔案中的zset-max-ziplist-entries、zset-max-ziplist-value選項進行調整,

原始碼閱讀

  1. 檔案:src/t_zset.c
隻言片語任我說,提筆句句無需忖。落筆不知寄何人,唯有邀友共斟酌。