type
status
date
slug
summary
tags
category
icon
password
Property
Redis
使用对象来表示数据库中的键和值, 每次在Redis
的数据库中新创建一个键值对时, 至少会创建两个对象, 一个对象用作键值对的键(键对象), 另一个对象用作键值对的值(值对象)。例如, SET命令在数据库中创建了一个新的键值对, 其中键值对的键是一个包含了字符串值
"msg"
的对象, 而键值对的值则是一个包含了字符串值"hello world"
的对象:Redis
中的每个对象都由一个redisObject
结构表示, 该结构中和保存数据有关的三个属性分别是type
属性、encoding
属性和ptr
属性:类型
对象的
type
属性记录了对象的类型, 这个属性的值可以是下表列出的常量的其中一个:类型常量 | 对象的名称 |
REDIS_STRING | 字符串对象 |
REDIS_LIST | 列表对象 |
REDIS_HASH | 哈希对象 |
REDIS_SET | 集合对象 |
REDIS_ZSET | 有序集合对象 |
对于
Redis
数据库保存的键值对来说, 键总是一个字符串对象, 而值则可以是字符串对象、列表对象、哈希对象、集合对象或者有序集合对象的其中一种:- 当称呼一个数据库键为“字符串键”时, 指的是“这个数据库键所对应的值为字符串对象”
- 当称呼一个键为“列表键”时, 指的是“这个数据库键所对应的值为列表对象”
TYPE
命令的实现方式也与此类似, 对一个数据库键执行TYPE
命令时, 命令返回的结果为数据库键对应的值对象的类型, 而不是键对象的类型:不同类型值对象的
TYPE
命令输出:对象 | 对象 type 属性的值 | TYPE 命令的输出 |
字符串对象 | REDIS_STRING | "string" |
列表对象 | REDIS_LIST | "list" |
哈希对象 | REDIS_HASH | "hash" |
集合对象 | REDIS_SET | "set" |
有序集合对象 | REDIS_ZSET | "zset" |
编码和底层实现
对象的
ptr
指针指向对象的底层实现数据结构, 而这些数据结构由对象的encoding
属性决定。encoding
记录了对象所使用的编码, 即对象使用了什么数据结构作为对象的底层实现:编码常量 | 编码所对应的底层数据结构 |
REDIS_ENCODING_INT | long 类型的整数 |
REDIS_ENCODING_EMBSTR | embstr 编码的简单动态字符串 |
REDIS_ENCODING_RAW | 简单动态字符串 |
REDIS_ENCODING_HT | 字典 |
REDIS_ENCODING_LINKEDLIST | 双端链表 |
REDIS_ENCODING_ZIPLIST | 压缩列表 |
REDIS_ENCODING_INTSET | 整数集合 |
REDIS_ENCODING_SKIPLIST | 跳跃表和字典 |
每种类型的对象都至少使用了两种不同的编码,每种类型的对象可以使用的编码:
类型 | 编码 | 对象 |
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 | 使用跳跃表和字典实现的有序集合对象 |
使用
OBJECT ENCODING
命令可以查看一个数据库键的值对象的编码:OBJECT ENCODING
对不同编码的输出:对象所使用的底层数据结构 | 编码常量 | OBJECT ENCODING 命令输出 |
整数 | REDIS_ENCODING_INT | "int" |
embstr 编码的简单动态字符串(SDS) | REDIS_ENCODING_EMBSTR | "embstr" |
简单动态字符串 | REDIS_ENCODING_RAW | "raw" |
字典 | REDIS_ENCODING_HT | "hashtable" |
双端链表 | REDIS_ENCODING_LINKEDLIST | "linkedlist" |
压缩列表 | REDIS_ENCODING_ZIPLIST | "ziplist" |
整数集合 | REDIS_ENCODING_INTSET | "intset" |
跳跃表和字典 | REDIS_ENCODING_SKIPLIST | "skiplist" |
通过
encoding
属性来设定对象所使用的编码, 而不是为特定类型的对象关联一种固定的编码, 极大地提升了Redis
的灵活性和效率, 因为Redis
可以根据不同的使用场景来为一个对象设置不同的编码, 从而优化对象在某一场景下的效率。举在列表对象包含的元素比较少时,
Redis
使用压缩列表作为列表对象的底层实现:- 因为压缩列表比双端链表更节约内存, 并且在元素数量较少时, 在内存中以连续块方式保存的压缩列表比起双端链表可以更快被载入到缓存中
- 随着列表对象包含的元素越来越多, 使用压缩列表来保存元素的优势逐渐消失时, 对象就会将底层实现从压缩列表转向功能更强、也更适合保存大量元素的双端链表上面
其他类型的对象也会通过使用多种不同的编码来进行类似的优化