Redis 使用对象来表示数据库中的键和值, 每次当我们在 Redis 的数据库中新创建一个键值对时, 我们至少会创建两个对象, 一个对象用作键值对的键(键对象), 另一个对象用作键值对的值(值对象)。
举个例子, 以下 SET 命令在数据库中创建了一个新的键值对, 其中键值对的键是一个包含了字符串值 "msg"
的对象, 而键值对的值则是一个包含了字符串值 "hello world"
的对象:
redis> SET msg "hello world"
Redis 中的每个对象都由一个 redisObject
结构表示, 该结构中和保存数据有关的三个属性分别是 type
属性、 encoding
属性和 ptr
属性:
typedef struct redisObject { unsigned type:4; //类型 unsigned encoding:4; //编码 unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */ int refcount; //引用计数 void *ptr; //指向底层实现数据结构的指针 } robj;
- type: 对象的数据类型。占4个bit。可能的取值有5种:OBJ_STRING, OBJ_LIST, OBJ_SET, OBJ_ZSET, OBJ_HASH,分别对应Redis对外暴露的5种数据结构。
- encoding: 对象的内部表示方式(也可以称为编码)。占4个bit。可能的取值有10种,即前面代码中的10个OBJ_ENCODING_XXX常量。
- lru: 做LRU替换算法用,占24个bit。这个不是我们这里讨论的重点,暂时忽略。
- refcount: 引用计数。它允许robj对象在某些情况下被共享。
- ptr: 数据指针。指向真正的数据。比如,一个代表string的robj,它的ptr可能指向一个sds结构;一个代表list的robj,它的ptr可能指向一个quicklist。
使用redisObject的优点: 1) 为多种数据类型提供一种统一的表示方式。 2) 允许同一类型的数据采用不同的内部表示,从而在某些情况下尽量节省内存。 3) 支持对象共享和引用计数。当对象被共享的时候,只占用一份内存拷贝,进一步节省内存。
这里特别需要仔细察看的是encoding字段。对于同一个type,还可能对应不同的encoding,这说明同样的一个数据类型,可能存在不同的内部表示方式。而不同的内部表示,在内存占用和查找性能上会有所不同,下文将给出对应关系。
- 对象的
type
属性记录了对象的类型
/* Object types */ #define OBJ_STRING 0 // 字符串对象 Type “string” #define OBJ_LIST 1 // 列表对象 Type "list" #define OBJ_SET 2 // 集合对象 Type "set" #define OBJ_ZSET 3 // 有序集合对象 Type "zset" #define OBJ_HASH 4 // 哈希对象 Type "hash"
对于 Redis 数据库保存的键值对来说, 键总是一个字符串对象, 而值则可以是字符串对象、列表对象、哈希对象、集合对象或者有序集合对象的其中一种, 因此:
- 当我们称呼一个数据库键为“字符串键”时, 我们指的是“这个数据库键所对应的值为字符串对象”;
- 当我们称呼一个键为“列表键”时, 我们指的是“这个数据库键所对应的值为列表对象”,
诸如此类。
- 对象的 Encoding 属性记录了对象的编码,它决定对象的 ptr 指针指向对象的底层实现数据结构
// string采用原生的表示方式,即用sds来表示 #define OBJ_ENCODING_RAW 0 /* Raw representation */ // string采用数字的表示方式,实际上是一个long型 #define OBJ_ENCODING_INT 1 /* Encoded as integer */ // hash采用一个dict来表示 #define OBJ_ENCODING_HT 2 /* Encoded as hash table */ // 是个旧的表示方式,已不再用。在小于Redis 2.6的版本中才有 #define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */ //双端链表 #define OBJ_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */ //压缩列表 #define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */ //整数集合 #define OBJ_ENCODING_INTSET 6 /* Encoded as intset */ //跳跃表 #define OBJ_ENCODING_SKIPLIST 7 // Encoded as skiplist */ // string采用一种特殊的嵌入式的sds来表示 #define OBJ_ENCODING_EMBSTR 8 //Embedded sds string encoding embstr */ // 表示成quicklist。用于list数据结构 #define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
- 类型与编码对应关系
类型 | 编码 | 对象 |
---|---|---|
OBJ_STRING |
OBJ_ENCODING_INT |
使用整数值实现的字符串对象。 |
OBJ_STRING |
OBJ_ENCODING_EMBSTR |
使用 embstr 编码的简单动态字符串实现的字符串对象。 |
OBJ_STRING |
OBJ_ENCODING_RAW |
使用简单动态字符串实现的字符串对象。 |
OBJ_LIST |
OBJ_ENCODING_QUICKLIST |
用于list数据结构。(3.0版本后使用,之前的版本对应ziplist或linkedlist) |
OBJ_HASH |
OBJ_ENCODING_ZIPLIST |
使用压缩列表实现的哈希对象。 |
OBJ_HASH |
OBJ_ENCODING_HT |
使用字典实现的哈希对象。 |
OBJ_SET |
OBJ_ENCODING_INTSET |
使用整数集合实现的集合对象。 |
OBJ_SET |
OBJ_ENCODING_HT |
使用字典实现的集合对象。 |
OBJ_ZSET |
OBJ_ENCODING_ZIPLIST |
使用压缩列表实现的有序集合对象。 |
OBJ_ZSET |
OBJ_ENCODING_SKIPLIST |
使用跳跃表和字典实现的有序集合对象。 |
Pingback引用通告: Redis中的有序集合对象(Zset) | 精彩每一天
Pingback引用通告: Redis中的集合对象(Set) | 精彩每一天
Pingback引用通告: Redis中的哈希对象(Hash) | 精彩每一天
Pingback引用通告: Redis中的列表对象(List) | 精彩每一天