Redis - 資料型別對映底層結構

程式設計師翔仔發表於2023-04-21

簡介

從資料型別上體現就是,同一個資料型別,在不同的情況下會使用不同的編碼型別,底層所使用的的資料結構也不相同。

Redis 物件結構

字串物件

字串物件的編碼可以是 intrawembstr 三者之一。

embstr 編碼是專門用於儲存簡短字串的一種最佳化編碼方式,與 raw 編碼會呼叫兩次記憶體分配函式分別建立 redisObject 結構和 sdshdr 結構不同,embstr 只會使用一次記憶體分配函式建立一塊連續的記憶體空間同時存放 redisObject 結構和 sdshdr 結構。

字串轉換編碼的條件如下:

  • 如果字串物件儲存的是整數值並且不超過 long 的範圍時,優先選擇使用 int 作為編碼方式
  • 如果儲存的字串長度大於 32 個位元組,會使用 raw 編碼的簡單動態字串作為儲存
  • 如果儲存的字串長度小於 32 個位元組,會使用 embstr 編碼的簡單動態字串作為儲存

字串物件中有兩個需要注意的地方:

  • 對於儲存浮點數的字串物件,實際上這個浮點數是以字串值來儲存的,執行如 INCRBYFLOAT 這樣的命令時,Redis 會先將字串轉換成浮點數計算,然後再轉換成字串值儲存
  • int 編碼和 embstr 編碼在條件滿足下會轉換成 raw 編碼。embstr 在執行修改命令之後總是會轉換成 raw 編碼,這個過程是不可逆的

列表物件

在 3.2 版本之前,列表物件的編碼可以是 ziplist 或者 zlinkedlist 的其中一個;在 3.2 版本之後,列表物件的編碼只能是 quicklist

雜湊物件

雜湊物件的編碼可以是 ziplist 或者 hashtable 中的一個。

雜湊物件使用 ziplist 作為底層實現的時候,每當有新的鍵值對要插入雜湊物件時,Redis 會先儲存鍵的壓縮列表節點到壓縮列表的表尾,然後再儲存值的壓縮列表節點到壓縮列表的表尾。

當雜湊物件同時滿足以下兩個條件時,雜湊物件使用 ziplist 編碼:

  • 雜湊物件儲存的所有鍵值對的鍵和值的字串長度都小於 64 位元組
  • 雜湊物件儲存的鍵值對數量小於 512 個

集合物件

集合物件的編碼可以是 intset 或者 hashtable 中的一個。

hashtable 編碼的集合物件使用字典作為底層實現,字典的每個鍵都是字串物件,這個字串物件包含著集合元素,字典的每個值都直接儲存 NULL

當集合物件同時滿足以下兩個條件時,集合物件使用 intset 編碼:

  • 集合物件儲存的所有元素都是整數值
  • 集合物件儲存的元素資料不超過 512 個

有序集合物件

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

有序集合物件使用 ziplist 編碼作為底層實現時,每個集合物件會使用兩個緊挨在一起的壓縮列表節點來儲存,第一個節點儲存元素的成員,第二個元素則儲存元素的分值。

這裡有一點需要注意,skiplist 編碼的有序集合使用 zset 結構作為底層實現,一個 zset 結構包含一個字典和一個跳錶。其中字典的鍵儲存元素的成員,字典的值儲存元素的分值;跳錶的 object 屬性儲存元素的成員,跳錶的 score 屬性儲存元素的分值。

理論上有序集合可以只使用字典或者跳錶實現,但是使用兩個結構冗餘儲存有序集合物件的成員和分值,既保留了字典 \(O(1)\) 時間複雜度查詢的效率,也保留了跳錶範圍型操作的所有優點。

當同時滿足以下兩個條件時,有序集合會使用 ziplist 編碼:

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

相關文章