redis 系列9 物件型別(字串,雜湊,列表,集合,有序集合)與資料結構關係
一.概述
在前面章節中,主要了解了 Redis用到的主要資料結構,包括:簡單動態字串、連結串列(雙端連結串列)、字典、跳躍表、 整數集合、壓縮列表(後面再瞭解)。Redis沒有直接使用這些資料結構來實現鍵值對資料庫,而是基於這些資料結構建立一個物件系統,這個系統物件包括:字串物件、列表物件、雜湊物件(雜湊)、集合物件、有序集合物件這五種型別,每種型別物件都用到了至少一種前面所介紹的資料結構。
通過這五種不同型別的物件,可以針對不同的使用場景, 在Redis 內部會為物件設定不同的資料結構實現,從而優化物件在不同場景下的使用效率。下面先直觀看下關係圖(五種物件與type與encoding編碼與ptr底層資料結構),然後再來詳細介紹它們之間的關係。
二. 物件型別與編碼(五種型別的物件)
Redis中的每個物件都由一個RedisObject結構表示,該結構中和儲存資料有關的三個屬性分別是type屬性、encoding屬性、ptr屬性。
typeof struct redisObject{ //型別 unsigned type:4; //編碼 unsigned encoding:4; //指向底層實現資料結構的指標 void *ptr;//... }robj;
2.1 type型別
物件的type屬性記錄了物件的型別,對於鍵來說它總是一個字串物件,而值可以是五種型別,這五種型別如下表格:
type取值的型別常量 |
五種物件的名稱 |
Type命令輸出 |
Redis_string |
字串物件 |
string |
Redis_list |
列表物件 |
list |
Redis_hash |
雜湊物件 |
hash |
Redis_set |
集合物件 |
set |
Redis_zset |
有序集合物件 |
zset |
例1: 下面使用type命令,該命令返回結果為資料庫鍵對應的值物件型別,而不是鍵物件的型別。
-- 值為字串物件 127.0.0.1:6379> set msg "hello world" OK 127.0.0.1:6379> type msg string -- 值為列表物件 127.0.0.1:6379> rpush number 1 3 5 (integer) 3 127.0.0.1:6379> type number list -- 值為雜湊物件 127.0.0.1:6379> hmset profile name tom age 25 career programmer OK 127.0.0.1:6379> type profile hash -- 值為集合物件 127.0.0.1:6379> sadd fruit apple banana cherry (integer) 3 127.0.0.1:6379> type fruit set -- 值為有序集合物件 127.0.0.1:6379> zadd price 8.50 apple 3.30 banana (integer) 2 127.0.0.1:6379> type price zset
2.2 編碼和底層實現(encoding, ptr)
物件的ptr指標指向物件的底層實現資料結構,而這些資料結構由物件的encoding屬性決定,encoding記錄了物件所使用的編碼。使用object encoding命令檢視不同編碼的輸出。表格如下:
(1) 底層資料結構與encoding編碼的對應關係:
底層資料結構 |
encoding編碼常量取值 |
object encoding 輸出 |
整數 |
Redis_encoding_int |
int |
Embstr編碼的SDS字串(長字元值) |
Redis_encoding_embstr |
embstr |
SDS字串 |
Redis_encoding_raw |
raw |
字典 |
Redis_encoding_ht |
hashtable |
連結串列 |
Redis_encoding_linkedlist |
linkedlist |
壓縮列表 |
Redis_encoding_ziplist |
ziplist |
整數集合 |
Redis_encoding_intset |
intset |
跳躍表和字典 |
Redis_encoding_skiplist |
skiplist |
(2) 五種物件型別與encoding編碼的對應關係
五種物件型別常量 |
對應encoding編碼常量 |
物件說明 |
Redis_string |
Redis_encoding_int |
使用整數值實現的字串物件 |
Redis_string |
Redis_encoding_embstr |
使用embstr編碼的簡單動態字串實現的字串物件 |
Redis_string |
Redis_encoding_raw |
使用簡單動態字串實現的字串物件 |
Redis_list |
Redis_encoding_ziplist |
使用壓縮列表實現的列表物件 |
Redis_list |
Redis_encoding_linkedlist |
使用雙端連結串列實現的列表物件 |
Redis_hash |
Redis_encoding_ziplist |
使用壓縮列表實現的雜湊物件 |
Redis_hash |
Redis_encoding_ht |
使用字典實現的雜湊物件 |
Redis_set |
Redis_encoding_intset |
使用整數集合實現的集合物件 |
Redis_set |
Redis_encoding_ht |
使用字典實現的集合物件 |
Redis_zset |
Redis_encoding_ziplist |
使用壓縮列表實現的有序集合物件 |
Redis_zset |
Redis_encoding_skiplist |
使用跳躍表和字典實現的有序集合物件 |
例2: 下面使用object encoding命令,該命令檢視一個數據庫鍵的值物件的編碼:
127.0.0.1:6379> set msg "hello wrold" OK 127.0.0.1:6379> object encoding msg "embstr" 127.0.0.1:6379> set story "long long long long long long long long long ..." OK 127.0.0.1:6379> object encoding story "raw" 127.0.0.1:6379> sadd num 1 3 4 (integer) 0 127.0.0.1:6379> object encoding num "intset" 127.0.0.1:6379> sadd num 1 3 4 "one" (integer) 1 127.0.0.1:6379> object encoding num "hashtable" 127.0.0.1:6379> zadd fruit-price 5.0 banana 6.5 cherry 8.0 apple (integer) 0 127.0.0.1:6379> object encoding fruit-price "ziplist" 127.0.0.1:6379> rpush integers "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" (integer) 20 127.0.0.1:6379> object encoding integers "quicklist"
總結:通過encoding屬性來設定物件所使用的編碼,而不是為特定型別的物件關聯一種固定的編碼,極大提升了redis的靈活性和效率。例如:上面演示的zadd fruit-price 新增列表元素,redis使用壓縮列表作為列表物件的底層實現,因為壓縮列表比連結串列更節約記憶體,並且在元素數量較少時,在記憶體中以連續塊方式儲存的壓縮列表比連結串列可以更快被載入到快取中。但隨著列表物件元素越來越多時,這種壓縮優勢就會消失,此時物件就會將底層實現從壓縮列表轉向連結串列。 其它型別的物件也會通過使用多種不同的編碼來進行類似的優化。
使用物件key通過Type命令檢視value值的物件型別,通過object encoding命令檢視value值的底層資料結構。