簡介
從數據類型上體現就是,同一個數據類型,在不同的情況下會使用不同的編碼類型,底層所使用的的數據結構也不相同。
字符串對象
字符串對象的編碼可以是?int
、raw
?和?embstr
?三者之一。
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 字節
?