一篇讲清Redis中常见数据类型的用法
目录
string
SET命令
GET命令
MSET命令
MGET命令
INCR命令
INCRBY命令
DECR命令
DECRBY命令
INCRBYFLOAT命令
APPEND命令
GETRANGE命令
SETRANGE命令
STRLEN命令
命令小结
内部编码
int
embstr
raw
典型应用场景
缓存功能
计数功能
共享会话
手机验证码
hash
HSET命令
HGET命令
HEXISTS命令
HDEL命令
HKEYS命令
HVALS命令
HGETALL命令
HMGET命令
HSCAN命令
HLEN命令
HSETNX命令
HINCRBY命令
HINCRBYFLOAT命令
命令小结
内部编码
应用场景
list
LPUSH命令
LRANGE命令
LPUSHX命令
RPUSH命令
RPUSHX命令
LPOP命令
RPOP命令
LINDEX命令
LINSERT命令
LLEN命令
LREM命令
LTRIM命令
LSET命令
阻塞命令
命令小结
内部编码
应用场景
消息队列
分频道的消息队列
set
SADD命令
SCARD命令
SMEMBERS命令
SISMEMBER命令
SPOP命令
SRANDMEMBER命令
SMOVE命令
SREM命令
集合操作命令
SINTER命令
SINTERSTORE命令
SUNION命令
SUNIONSTORE命令
SDIFF命令
SDIFFSTORE命令
命令小结
内部编码
应用场景
zset
ZADD命令
ZRANGE命令
ZREVRANGE命令
ZRANGEBYSCORE命令
ZCARD命令
ZCOUNT命令
ZPOPMAX命令
ZPOPMIN命令
ZRANK命令
ZREVRANK命令
ZSCORE命令
ZREM命令
ZREMRANGEBYRANK命令
ZREMRANGEBYSCORE命令
ZINCRBY命令
阻塞命令
BZPOPMAX命令
BZPOPMIN命令
集合操作命令
zinterstore命令
zunionstore命令
命令小结
内部编码
应用场景
其他数据类型
stream
geospatial
hyperloglog
bitmaps
bitfields
渐进式遍历
string
redis中的字符串,直接就是按照二进制数据方式存储的,不会做任何编码转换,存的是什么,取出来还是什么。
SET命令
SET key value [expiration EX seconds | PX milliseconds] [NX|XX]
SET key value ex 10 相当于 SET key value + expire key 10
设置了存活时间可以用ttl命令来查看剩余的存活时间,返回的值的单位为秒,如果key没设置ex则返回的是-1,如果这个key存活时间结束,返货的是-2
NX:如果key不存在才设置,如果key存在则不设置返回nil
XX:如果key存在才设置,如果key不存在则不设置返回nil
SETNX 为 SET key value NX 简写,不存在才设置成功,存在则设置失败
SETEX 为 SET key value EX 简写,设置key存活的秒数。
PSETEX 为 SET key value PX 简写,设置key存活的毫秒数。
注意:使用set的时候,如果key存在,会让新的value覆盖旧的value,可能会改变原本的数据类型,原来这个key的ttl也会时效。
GET命令
get key
对于GET来说,它只支持字符串类型的value,对于其他类型,使用GET获取就会出错。
MSET命令
mset key1 value1 key2 value2 key3 value3 ....
一次可以set多个键值对
时间复杂度:O(N) N为key的数量,但也通常认为是O(1)。
MGET命令
mget key1 key2 key3 ...
一次可以取出多个value
时间复杂度:O(N) N为key的数量。
INCR命令
incr key
针对key对应的value+1,返回值为value+1的值
注意:自增的数必须是整数,并且不能超过64位/8字节的整数范围。
其他类型不能自增
超过范围也不能自增
incr操作的key如果不存,就会把key的value当作0进行增加
INCRBY命令
incrby key n
针对key对应的value进行+n操作,返回值为+n的值
注意事项和incr相同。
但incrby能够加负数,达到减法的效果
DECR命令
decr key
针对key对应的value进行-1操作,返回值为-1后的值
注意事项和上面类似。
DECRBY命令
decrby key n
针对key对应的value值进行-n的操作,返回值为-n的值
注意事项同上,并且decrby命令也能实现加法
INCRBYFLOAT命令
incrbyfloat key n
针对key对应的value进行+或者-运算,返回值为运算后的值
同时也能实现减法
increbyfloat不仅能处理小数,同时也可以处理整数加减,但是目前没有所对应的decrbyfloat命令。
小结:上述所有进行加减的命令都只能针对整数,除了increbyfloat可以针对小数有效,并且都不能超过64位所能表示的范围,所有的时间复杂度也为O(1)。
在redis处理命令的时候也不用担心修改数据引起的线程安全问题,因为redis为单线程模型。
APPEND命令
append key s
针对字符串进行追加,返回值为追加后的字符串长度(单位为字节)
如果key不存在,那么相当于使用set创建了一个字符串
注意:对于redis字符串,因为redis不会对字符编码做任何处理,存进去什么样,取出来就什么样,因此在存储中文字符的时候,也是同样如此
我这里使用的是Xshell终端,默认字符集是utf8,因此在终端输入汉字后,redis也就安装utf8编码存储数据,这里显示的就是对应的utf8编码的十六进制数据。
为了避免自己转化的麻烦,可以在启动redis终端的时候添加--raw这样的选项,就可以使redis客户端能够自动的把二进制数据尝试解码翻译。
GETRANGE命令
getrange key start end
针对字符串进行截取,由start 和 end 两个参数指定范围,返回值为截取后的字串
其中start和end表示的区间为闭区间,和Java或者C++大部分编程语言稍微不太一样,这里为左闭区右闭。
并且区间也可以写成负数,例如-1表示倒数第1个字符
但如果start或者end两个都超出了字符串长度的范围返回的则是空串
注意:redis中存储的是二进制数据,操作是以一个字节为单位,不是一个字符,因此在getrange中文字符的时候就会出现问题。
SETRANGE命令
setrange key offset value
针对字符串进行指定范围替换,offset为偏移量表示开始替换的起始位置,替换的长度取决于value,返回值为替换后的新的字符串长度
setrange也能对不存在的key进行操作,对不存在的key操作相当于创建了一个key和value,并且offset之前的会被填充为0
STRLEN命令
strlen key
针对字符串获取字符串长度,返回值为字符串长度
注意:这里字符串长度单位是字节(C++中,字符串长度本身就是以字节为单位,而Java字符串是以字符为单位,Java一个char==2个字节)
此处使用的Xshell终端默认编码方式是uft8一个中文字符占3个字节
strlen只能对字符串起作用,其他类型则会报错
命令小结
内部编码
查看内部编码命令
object encoding key
int
当存储的字符串是8个字节的长整型的时候,redis使用的内部编码为int
embstr
当存储的字符串长度小于等于某个字节长度时,redis内部编码为embstr,表示压缩字符串的方式,能够节省空间
raw
当存储的字符串长度大于某个字节长度时,redis内部编码为raw,表示普通类型的字符串
注意:embstr和raw编码转化的临界值没有具体的值,在实际工作中一般是可以进行动态调整的,并且在redis6及以前的版本中这个临界值默认是39,而我目前使用的是redis7,经过测试是在字符串长度到达45的时候发生变化的,因此去记住具体的值是没有意义的。
拓展:redis存储小数的时候本质上还是字符串
如果用字符串存小数,那么在每次计算的时候,都需要把字符串转成小数,计算完毕后,结果又转成字符串进行保存,两次转化也会增加开销。
典型应用场景
缓存功能
例如Redis+MySQL构成缓存架构
Redis作为缓存,空间相对较小,当每把数据写入Redis中时,同时也会设置一个过期时间,Redis会根据内存淘汰策略,释放空间确保内存够用。
计数功能
例如统计视频播放次数
它可以实现快速计数、查询缓存的功能,同时数据可以异步处理或者落地到其他数据源。
共享会话
session的集中管理
通过Redis可以使用会话集中管理,这样每次用户请求的不到不同的服务器都能做出合理的响应,保证了Redis的高可用和扩展性。
手机验证码
最主要的是key可以设置过期时间
hash
哈希类型中的映射关系通常称为 field-value,用于区分 Redis 整体的键值对(key-value),注意这里的 value 是指 field 对应的值,不是键(key)对应的值。
HSET命令
hset key field1 value1 [field2 value2 ...]
添加hash类型的数据,可以一次设置多个,返回值为设置成功的个数
HGET命令
hget key field
获取key中的哈希表中field的值,返回值为value值,如不存在则返回nil
HEXISTS命令
hexists key field
判断key中的field是否存在,返回1表示存在,0表示不存在
HDEL命令
hdel key field [field ...]
删除key中指定的field,返回值为删除成功的个数
注意:hdel是删除key的field,而del是删除key。
HKEYS命令
hkeys key
获取hash中所有的字段,返回值为字段列表
这个操作是根据key找到对应的hash,O(1),然后在遍历hash,O(N)。如果hash中的字段多这个操作也存在一定风险,和keys *类似数据过多可能会造成redis服务器阻塞。
HVALS命令
hvals key
返回值为可hash中所有字段的value值
这个操作的时间复杂度和hkeys相同。
HGETALL命令
hgetall key
获取到key中所有的field和对应的value,返回值为fileld和value相邻输出的列表
HMGET命令
hmget key field [field ...]
查询key中指定的field字段,返回对应字段value的列表
HSCAN命令
hscan key cursor
hscan命令可以避免发生一次性处理大量数据而造成redis服务器阻塞,上述的hkeys,hvals,hgetall会获取所有数据,在数据比较庞大时极有可能会造成服务器阻塞,而hscan则是能够做到分批查询。
其中cursor表示游标,说明遍历的位置,返回值第一个数为下次开始遍历的位置
HLEN命令
hlen key
获取key中的hash键值对的个数
HSETNX命令
hsetnx key field vlaue
field字段不存在时才设置成功,成功返回1,失败返回0
HINCRBY命令
hincrby key field n
对hash中field对的value进行加减整数n,返回值为加减结果后的值
HINCRBYFLOAT命令
hincrbyfloat key field n
对hash中field对的value进行加减小数n,返回值为加减结果后的值
命令小结
内部编码
listpack是对hash表中的元素进行压缩(redis6之前是ziplist),能够节省一定内存空间,但是listpack付出的代价是在进行读写的时候速度相对来说会比较慢
如果哈希表中元素个数比较少,会使用listpack表示,元素个数比较多会转成hashtable。
如果每个vlaue的值的长度都比较短,使用listpack表示,value的长度太长了也会转成hashtable。
转换的配置可以根据实际需求在redis.conf配置文件中,修改hash-max-ziplist-entries(默认值为512个)配置根据元素个数转换条件,修改hash-max-ziplist-value(默认值为64字节长度)配置根据value值的长度转化条件。(配置文件默认地址:/etc/redis/redis.conf)
应用场景
作为缓存
hash结构更适合存储一些结构化的数据
数据库如果存在一张这样的表结构,我们可以使用redis像下面方式进行存储
这样的存储string类型也能做到,需要使用json的格式存储,但在转换的过程中没有hash方便直接。
使用string和hash作为缓存的对比
string缺点:如果需要读取/修改其中的某一个字段,需要将整个字符串读取出来然后进行转化成对象,读取/修改后再转会字符串子存回去,这样序列化和反序列化开销大,过程也繁琐,不灵活。
hash缺点:需要控制listpack和hashtable两种编码转换,空间开销可能比较大。
string优点:内存呢使用效率比较高。
hash优点:简单、直观、灵活。尤其是针对信息的局部变更或者获取操作。
list
list数据类型类似于数组或顺序表,内部的编码方式类似于双端队列
LPUSH命令
lpush key element [element ...]
将一个或者多个元素从左侧插入(头插)到list中,如果key不存在自动创建一个key,返回值为插入后list的长度
LRANGE命令
lrange key start syop
查看list的中指定的范围的元素,区间范围为闭区间,下标同样支持负数
LPUSHX命令
lpush key element [element ...]
若key存在时,将一个或者多个元素从左侧放入,不存在则直接返回,返回值是插入后list的长度
key不存在的情况
RPUSH命令
rpush key element [element...]
将一个或者多个元素从右侧插入(尾插)到list中,如果key不存在自动创建一个key,返回值为插入后list的长度
RPUSHX命令
rpushx key element [element...]
若key存在时,将一个或者多个元素从右侧放入,不存在则直接返回,返回值是插入后list的长度
key不存在的情况
LPOP命令
lpop key [count]
从list左侧取出一个元素(头删),参数count可以指定要删除的个数,返回值为取出的元素或nil
RPOP命令
rpop key [count]
从list右侧取出一个元素(尾删),参数count可以指定要删除的个数,返回值为取出的元素或nil
LINDEX命令
lindex key index
给定下标,获取到对应的元素,时间复杂度O(N),如果下标非法返回的是nil
LINSERT命令
linsert key <before|after> privot elment
在基准值(privot)的前面(before)或者后面(after),插入元素(elment),返回值表示插入之后新的list的长度
如果基准值不存在则返回-1
注意:这个基准值是从左往右找到的第一个元素。
LLEN命令
llen key
计算list的长度并返回,如果key不存在则返回0
LREM命令
lrem key count element
删除list中count数量个的element元素,返回删除后list的长度
注意:
count>0时从左往右找count个元素进行删除
count<0时从右往左找-count个元素进行删除
count=0时删除所有的element元素。
LTRIM命令
ltrim key start stop
只保留list从start和stop区间的元素,区间外的两边元素就直接被删除了
LSET命令
lset key index element
根据下标修改元素,时间复杂度O(N),成功返回OK,index越界失败会报错
阻塞命令
<blpop|brpop> key [key...] timeout
blpop和brpop为lpop和rpop阻塞版本的命令,当元素为空时,lpop和rpop会返回nil,而blpop和brpop会根据timeout(单位秒)阻塞一段时间,再返回一个二元组(pair)包含key和key中返回的值。
命令中如果设置了多个key,redis会从左向右遍历,哪个key先有元素就返回哪个key的元素。
如果有多个客户端对同一个key进行阻塞pop,等key中有元素了后,哪个客户端最先发起的请求就给哪个客户端响应。
1.针对有元素的list
效果基本和lpop一样
2.针对list为空的情况
当指定的timeout时间到了客户端还没有添加元素就会返回nil
命令小结
内部编码
目前redis的list类型内部编码方式是quicklist
quicklist是由双向链表+多个 ziplist 的组合构成,当list中元素过多会转化成多个quicklist组合而成,具体多少元素才转化的可以根据配置文件进行修改,配置文件路径:/etc/redis/redis.conf
应用场景
消息队列
消费者采用轮询的策略获取元素,消费者通过“先到先得”这样的方式依次获取元素,当消费者拿到元素后会离开队列,如果再次想重新请求,就得重新排队。
分频道的消息队列
就例如刷视频的时候,会同时获取几个频道的信息,一个播放视频,一个这是显示弹幕,一个展示评论,这样同时也做到了解耦合。
set
set是一个无序集合,而list是属于有序集合,set集合中的元素是不重复的唯一的。
SADD命令
sadd key member [member...]
将key中加入元素,返回值为本次操作添加成功的个数
SCARD命令
scard key
求key集合中的元素个数
SMEMBERS命令
smembers key
查询出当前集合的所有元素
SISMEMBER命令
sismember key member
判断集合key中是否存在member这个元素,存在返回1,不存在返回0
SPOP命令
spop key [count]
随机删除key中一个或count个元素,返回值为被删除的那个数
SRANDMEMBER命令
srandmember key [count]
随机获取一个或count个key中的元素但不删除,返回值为随机获取的元素
SMOVE命令
smove source destination member
将source集合当中的member移动到destination集合中去,移动成功返回1,失败返回0
SREM命令
srem key member [memebr...]
删除集合中的一个或多个member,返回值为成功删除的个数
集合操作命令
集合的操作主要是求交集,并集,差集
SINTER命令
sinter key [key...]
求所有集合的交集,此处一个key对应一个集合,时间复杂夫为O(N*M),N为最小的集合元素个数,M为最大的集合元素个数,返回结果为交集后的元素
SINTERSTORE命令
sinterstore destination key [key...]
将算好的交集方在destination集合中,返回交集的个数
SUNION命令
sunion key [key...]
返回所有key并集的结果,时间复杂度O(N),N指的是总的元素个数,返回值为并集的结果
SUNIONSTORE命令
sunionstore destination key [key...]
直接把并集的结果保存到destination集合中,返回值为并集元素的个数
SDIFF命令
sdiff key [key...]
计算第一个key对后面的差集,结构跟key的顺序有关,时间复杂度O(N),返回值为差集的结果
SDIFFSTORE命令
sdiffstore destination key [key...]
将计算差集的结果保存到destination集合中,返回差集结果的个数
命令小结
内部编码
intset(整数集合)
当元素个数均为整数,并且元素的个数不是很多的时候,就会以intset作为内部编码,这种结构有特定的优化,能够节省空间
hashtable(哈希表)
当集合中包含其他除整数外的元素,或者集合个数较多时就会转化为哈希表的结构
应用场景
标签系统
短视频软件会将不同种类的视频抽象成一个个标签,根据每个用户在不同视频上的停留时间,来给当前用户打上不同标签,结合每个用户所属标签不同推送不同的视频。
信息去重
一个互联网产品在衡量用户量和用户规模时,会根据PV(page view) 指的是用户每次访问服务器都会产生一个PV, 还有一个UV(user view)同一个用户访问服务器只会产生一个UV,而这个UV去重的过程就是利用set来实现的。
社交网络
根据set有交集并集差集的特点,在社交软件中能够根据你当前的好友信息,向你推送你可能认识的人、显示共同好友,查找单方面好友。
zset
zset为有序集合,这里的有序指的是升序或者降序,set为无序,list为顺序,注意区分。
ZADD命令
zadd key [NX|XX] [GT|LT] [CH] [INCR] score member [score member...]
往有序集合中添加元素和分数
参数选项:
XX:只更新当前已经存在的member,不存在则操作失败
NX:只添加新的member,对已经存在的不做处理
不加XX|NX:member不存在就添加,存在就更新分数
LT:现在需要更新的分数必须比之前的分数小,否则更新失败(元素不存在时不阻止添加元素)
GT:现在需要更新的分数必须比之前的分数大,否则更新失败(元素不存在时不阻止添加元素)
CH:影响zadd的返回值,本来zadd返回的是新增成功的元素的个数,加上CH会包含修改值的个数
INCR:表示对某个成员的分数进行累加(增加),只能指定一个元素的成员,如果成员不存在,则相当于添加新成员。返回值会变成增加后的分数。
排序方式:zset内部是按照升序方式进行排列的。
修改分数,如果位置发生变化会重新排序
ZRANGE命令
zrange key start stop [withscores]
返回指定区间的元素,分数按照升序返回,withscores参数表示把元素对应的分数也带上返回
ZREVRANGE命令
zrevrange key start stop [withscores]
根据指定区间,按照分数降序返回
ZRANGEBYSCORE命令
zrevrangebyscore key min max [withscores]
根据分数区间来找元素,返回值为区间的元素和分数
ZCARD命令
zcard key
获取key中元素的个数,时间复杂度O(logN)
ZCOUNT命令
zcount key min max
返回分数在 min 和 max 之间的元素个数,默认情况下,min 和 max 都是包含的,时间复杂度O(logN),zcount在计算的时候,是现根据分数找到元素,在根据元素获取排名,再把排名相减,得到元素个数。返回值为符合要求元素的个数
但也可以通过 左括号( 来进行排除。
max和min都还可以写成浮点数,zset中支持使用-inf表示负无穷大,inf表示无穷大
ZPOPMAX命令
zpopmax key [count]
删除并返回分数最大的元素,也可设置删除的个数count,时间复杂度O(logN),虽然redis的有序集合记录了结尾的元素,但是删除的时候使用的通用的删除函数,导致出现了重新查找的过程。
ZPOPMIN命令
zpopmin key [count]
删除并返回分数最小的元素,也可以设置删除的个数count,时间复杂度O(logN)原理同zpopmax
ZRANK命令
zrank key member
获取集合中指定元素的排名下标(升序),时间复杂度O(logN),返回值为该membe对应的分数在有序集合中的排名下标的下标(下标从0开始)
ZREVRANK命令
zrevrank key member
获取集合中指定元素的排名下标(降序),时间复杂度O(logN),返回值为该membe对应的分数在有序集合中的排名的下标(下标从0开始)
ZSCORE命令
zscore key member
查询指定元素的分数,时间复杂度O(1),此处Redis进行了专门的优化,花费了额外的空间代价,提示了查询速度,返回值为对应元素的分数
ZREM命令
zrem key member [member...]
删除有序集合中指定的元素,时间复杂度为O(logN*M),返回值为删除成功的元素个数
ZREMRANGEBYRANK命令
zremrangebyrank key start stop
删除指定区间(排名下标)的元素,时间复杂度为O(logN+M),查询只需查询一次花费logN,N为整个有序集合的元素个数,M为start-stop区间中的元素个数,返回值为删除成功的元素个数
ZREMRANGEBYSCORE命令
zremrangebyscore key min max
删除指定分数范围的元素,时间复杂度O(logN+M),返回值为成功删除元素的个数
ZINCRBY命令
zincrby key increment member
对有序集合中指定的member进行增加increment分数(可以是负数也可以是小数),返回值为增加后的分数结果
阻塞命令
主要是zpopmax和zpopmin的阻塞版本
BZPOPMAX命令
bzpopmax key [key...] timeout
删除有序集合中,最大的一个元素,该命令为zpopmax的阻塞版本,timeout时间单位为秒,时间复杂度为O(logN),返回值包括key,member,score
如果有序表中存在元素,就会和zpopmax一样直接返回结果,如果key中没有元素了,则会进入阻塞等待
如果在timout时间内有元素被添加则会输出,如果没有则会返回nil
BZPOPMIN命令
bzpopmin key [key] timeout
删除有序集合中,最小的一个元素,该命令为zpopmin的阻塞版本,timeout时间单位为秒,时间复杂度为O(logN),返回值包括key,member,score
当有序表中存在元素那么效果和zpopmin一样,如果没有元素则会进入阻塞等待,当集合中有元素被添加则会唤醒返回元素,超过等待时间还没元素则会返回nil
集合操作命令
zset的集合操作包括zinter,zunion,zdiff,zinterstore,zunionstore,zdiffstore,这些操作命令和set中的集合操作命令类似,但是zset是针对元素member进行集合操作和分数score多少无关
zinterstore命令
zinterstore destination numkeys key [key...] [WEIGHTS weight [weight...] ] [AGGREGATE sum|min|max]
destination:表示交集过后的结果存放的位置key
numkeys:表示接下来要进行交集的key的数量
WEIGHTS:表示对每个key所占的权重
AGGREGATE:表示交集后member对应的score是多少,默认情况下是用到sum
时间复杂度O(N*K + M*log(M)),N
是输入的有序集合中元素数量最少的那个集合的大小,K是输入有序集合的数量,M是结果集中元素的数量
返回值为交集成功后包含的元素个数
下面是添加参数的用法
首先,根据每个key中元素的找到相同的member。
其次,因为设置了权重占比,那么key1的所有score就会乘1,key2的所有score就会乘2。
最后,AGGREGATE的参数为MAX,会根据通过权重计算后的score,最大的score方在key4中。
zunionstore命令
zunionstore destination numkeys key [key...] [WEIGHTS weight [weight...] ] [AGGREGATE sum|min|max]
求多个有序集合的并集并保存起来,参数和求交集相同,返回值为并集成功后包含的元素个数
命令小结
内部编码
如果有序集合中的元素个数较少,或者的单个元素体积较小,使用listpack来存储。如果当前元素个数比较多,或者单个元素体积非常大,使用skiplist来存储。
在redis的配置文件中可以设置skiplist跳表的条件,zset-max-listpack-entries表示元素的个数,zset-max-listpack-value表示元素的大小单位字节
应用场景
游戏排行榜
可以将每个游戏玩家的id和分数存储到有序集合中,通过分数进行排序,从而展示每个用户的排名。
微博热搜榜
热搜榜的维度可能是多方面的:阅读量、点赞量、转发量、评论量等多个维度获取,然后每个维度有不同的权重划分,在通过求并集方式得到最终热搜排行榜。
其他数据类型
stream
Redis 的 Stream 就是个能存流式数据的类型,类似于消息队列一样。
消息按顺序保存,有唯一 ID,掉电不丢失。
支持多组人同时消费,各看各的,消息处理完得确认。
能回头看历史消息,适合日志收集、实时传数据这些场景。
geospatial
Redis 的 GEO 类型专门用来存地理位置信息(比如经纬度)。
能方便地查两点距离、找某个范围内的地点,还能按距离排序。
适合做附近的人、周边店铺这类功能,用起来简单直接。
hyperloglog
Redis 的 HyperLogLog 是一种专门用来做基数统计的类型。
基数就是 “不重复的元素个数”,比如统计网站独立访客数。
它的特点是占内存极小,不管统计多少数据,大概就几 KB。
适合那些需要统计 “有多少不同个体,但不需要知道每个内容是啥”,又不想耗太多内存的场景。
精度存在一定误差,误差大概是0.81%
bitmaps
Redis 的 Bitmaps 是一种通过位(bit) 来存储数据的类型,本质是对字符串(String)的位操作封装。
它把数据按位记录(1 或 0),比如用 1 表示 “已签到”,0 表示 “未签到”。
优点是极度省内存(1 字节能存 8 个状态),适合做连续天数签到、用户在线状态等场景的统计。
核心是用位运算(如与、或、非)高效处理批量数据,比如统计 “连续 7 天都签到的用户”。
bitfields
Redis 的 BITFIELD 是个灵活的位操作命令。
bitfields可以理解成一串二进制序列(字节数组),同时可以把这个字节数组中的某几个位,赋予特定的含义,并且可以进行读取/修改/算术运算等相关操作。
能把二进制数据分成不同长度的 “小段”,直接读写、增减这些小段里的数值。
可以一次干多个操作,适合用少量位存多个小数据(比如等级、状态),省内存又方便。
渐进式遍历
对于数据量大的内容想要进行遍历,如果使用keys * 进行遍历可能会导致服务器阻塞,而渐进式遍历就是避免这一情况, 每一次只取到其中的一部分数据,多次遍历来获取所有数据。
渐进式遍历包含一组命令,但使用方法类似,只需了解最典型的scan命令即可掌握其他命令
scan cursor [MATCH pattern] [COUNT count] [TYPE type]
cursor:表示为光标,作为每一次遍历的其实位置,起始光标位置为0。
MATCH:通配符,和keys的参数一样
COUNT:给redis建议每一次需要得到的个数,redis不一定会按照设置count返回。
TYPE:指定遍历的key中value的类型。
返回值:返回下一次遍历的光标位置 和 输出的元素个数,返回值为0代表以及遍历结束了
注意:光标不是下标,光标是对于计算机自己能够清除接下来要遍历的位置,返回的光标结果可能会和想象中数组的下标不一致。
这里的渐进式遍历,在遍历过程中,不会在服务器这边存储任何的状态信息,此处的遍历是课随时终止的,不会对服务器产生任何的副作用。
注意:scan虽然解决了遍历的阻塞问题,但是在遍历过程中存在对集合的修改增加删除,可能导致遍历重复或者遗漏。