一、实验环境
二、问题描述
1.问题详情
127.0.0.1:6379> set a 5
OK
127.0.0.1:6379> type a
string
127.0.0.1:6379> object encoding a
int
127.0.0.1:6379> append a 666
4
127.0.0.1:6379> get a
5666
127.0.0.1:6379> object encoding a
raw
127.0.0.1:6379>
疑问:
对数字a进行字符串操作append 666后,编码为什么由int变成raw,而不是变成embstr。
说好的,字符串长度小于等于44,编码格式是embstr的?
2.知识点科普
Redis的embstr编码方式和raw编码方式在3.2版本之前是以39字节为分界的,后续版本以44为分界。
也就是说,在redis5.0.4版本中,如果一个字符串值的长度小于等于44字节,则按照embstr进行编码,否则按照raw进行编码。
验证结果:
明显看到长度为44时,编码是embstr;大于44时,字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串值, 并将对象的编码设置为 raw 。
127.0.0.1:6379> set w jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj 注:44个j
OK
127.0.0.1:6379> object encoding w
embstr
127.0.0.1:6379> set q jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj 注:45个j
OK
127.0.0.1:6379> object encoding q
raw
三、问题根源
《Redis设计与实现》 上说是因为embstr是只读的,任何修改操作都会转换成raw。
通过该答案也就是说,不单单int编码类型(type是string),进行字符串操作后,会自动转码为raw;对普通的短字符串(长度小于45个字节) 进行字符串操作后,编码格式也会发生改变(由原来的embstr变成raw)!
为了验证这个问题,继续往下看↓↓
四、验证答案
--数字案例,编码前后发生了变化
127.0.0.1:6379> set a 5
OK
127.0.0.1:6379> type a
string
127.0.0.1:6379> object encoding a
int
127.0.0.1:6379> append a 666
4
127.0.0.1:6379> get a
5666
127.0.0.1:6379> object encoding a
raw
--字符串案例,编码前后发生了变化
127.0.0.1:6379> set k hello
OK
127.0.0.1:6379> type k
string
127.0.0.1:6379> object encoding k 此时的编码是embstr
embstr
127.0.0.1:6379> append k world 对k进行字符串w的操作
10
127.0.0.1:6379> get k
helloworld
127.0.0.1:6379> object encoding k 果然k被操作后,编码变成了raw
raw
127.0.0.1:6379>
五、结论
《Redis设计与实现》 上说是因为embstr是只读的,任何修改操作都会转换成raw。
通过上面的试验结果,再次验证了这句话是正确的。
如果仅仅声明了一个字符串,长度小于45时,它的编码格式默认就是embstr,一旦被修改了,编码格式会自动提升为raw。
这个是redis的内部设计问题。