redis · 28 3 月, 2021 0

redis数据结构-字符串对象(string)

字符串对象

字符串对象编码

字符串对象的编码可以是int,raw或者embstr类型

int 型

如果一个字符串对象保存的是整数值, 并且这个整数值用long类型来表示, 那么字符串对象会将整数值保存在字符串对象结构的ptr属性里面, 并将字符串编码设置为int.

redis> set number 10086
 OK
 ​
 redis> OBJECT ENCODING number
 "int"

 

raw 型

如果字符串对象保存的是一个字符串值, 并且这个字符串值的长度大于32(在3.0版本测试为40)字节,那么字符串对象将使用一个简单动态字符串保存这个字符串值。 并将对象的编码设置为raw.

以下测试在:3.0.0版本上测试:

redis> set msg "Long, long age there lived a king ..."
 OK
 ​
 redis> STRLEN story
 (integer) 37
 ​
 redis> OBJECT ENCODING story
 "embstr"

 

embstr 型

如果字符串对象保存的是一个字符串值, 并且这个字符串值的长度小于等于32(3.0.0版本测试长度为40)字节, 那么字符串对象将使用embstr编码的方式来保存这个字符串值.

embstr和raw比较

  • 不同点

    • raw编码会调用两次内存分别来创建redisObjectsdshdr结构, 用于存储字符串对象.

    • embstr编码则通过调用一次内存分配函数来分配一块连续的空间, 空间依次包含redisObjectsdshdr两个结构.

  • 相同点

    • embstr编码和raw编码的字符串对象执行命令时产生的效果是相同的.

embstr的优势

  • embstr编码将创建字符串对象所需的内存分配次数从raw编码的两次降为一次

  • 释放embstr编码的字符串对象只需要调用一次内存释放函数, 而释放raw编码的字符串对象需要调用两次内存释放函数

  • 因为embstr编码的字符串对象的所有数据都保存在一块连续的内存里面, 所以这种编码的字符串对象比起raw编码的字符串独享能够更好地利用缓存带来的优势.

对浮点数的支持

可以用long double类型表示的浮点数在Redis中也是作为字符串值保存的。如果我们要保存一个浮点数到字符串里面, 那么程序要先将这个浮点数转换成字符串值, 然后保存转换所得的字符串值.

redis> set pi 3.14
 OK
 ​
 redis> OBJECT ENCODING pi
 "embstr"

 

浮点数的操作

在对浮点数执行操作时(如运算操作), Redis需要将保存的字符串转换为浮点数, 执行操作之后, 再将最后的结果转换为字符串值. 并继续保存在字符串对象里面。

redis>INCRBYFLOAT pi 2.0
 "5.14"
 ​
 redis> OBJECT ENCODING pi
 "embstr"

 

字符串对象保存各类型值的编码方式

编码
可以用long类型保存的整数 int
可以用long double类型保存的浮点数 embstr或者raw
字符串值或者因为太大而没办法用long类型表示的整数, 又或者因为长度太大而没办法用long double类型表示的浮点数 embstr或者raw

字符串对象编码的转换

  • int 编码的字符串对象和embstr编码的字符串对象在条件满足的情况下, 会被转换为raw编码的字符串对象.

  • 对int编码的字符串对象来说, 如果我们向对象执行了一些命令, 使得这个对象保存的不再是整数, 而是一个字符串, 那么字符串对象的编码将从int变为raw

  • 对于embstr编码的字符串没有任何修改的程序, 所以embstr编码的字符串对象实际上是只读的。

  • 当我们对embstr编码的字符串对象执行任何修改命令时, 程序会先将对象的编码从embstr转换为raw, 然后再执行修改命令. 所以embstr编码的字符串对象在执行修改命令之后, 总会变成一个raw编码的字符串对象。

字符串命令的实现

命令 int编码的实现方法 embstr编码的实现方法 raw编码的实现方法
SET 使用int编码保存值 使用embstr编码保存值 使用raw编码保存值
GET 拷贝对象所保存的整数值, 将这个拷贝转换成字符串信息, 然后想客户端返回这个字符串值 指向向客户端返回字符串 直接向客户端返回字符串值
APPEND 将对象转换成raw编码, 然后按raw编码的方式执行此操作 将对象转换成raw编码, 然后按raw编码的方式执行此操作 调用sdscatlen函数, 将给定字符串追加到现有字符串的末尾
INCRBYFLOAT 去除整数值并将其转换为long double类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来 取出字符串值并尝试将其转换成long double类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来。如果字符串值不能被转换成浮点数, 那么向客户端返回一个错误 取出字符串值并尝试将其转换成long double类型的浮点数, 对这个浮点数进行加法计算, 然后将得出的浮点数结果保存起来。如果字符串值不能被转换成浮点数, 那么向客户端返回一个错误
INCRBY 对证书值进行加法计算, 得出的计算结果会作为整数保存起来 embstr编码不能执行此命令, 客户端返回一个错误 raw编码不能执行此命令, 向客户端返回一个错误
DECRBY 对整数值进行减法计算, 得出的计算结果会作为整数倍保存起来 embstr编码不能执行此命令, 向客户端返回一个错误 raw编码不能执行此命令, 想客户端返回一个错误
STRLEN 拷贝对象所保存的整数值, 将这个拷贝转换成字符串值, 计算并返回这个字符串值的长度 调用sdslen函数, 返回字符串长度 调用sdslen函数, 返回字符串的长度
SETRANGE 将对象转转成raw编码, 然后按raw编码的方式执行此命令 将对象转转成raw编码, 然后按raw编码的方式执行此命令 将字符串特定索引上的值设置为给定的字符
GETRANGE 拷贝对象所保存的整数值, 将这个拷贝转换成为字符串值, 然后取出并返回字符串指定索引上的字符 直接取出返回字符串指定索引上的字符 直接取出并返回字符串指定索引上的字符