目录
Set(集合)
集合类型也是保存多个字符串类型的元素的,但和列表类型不同的是,集合中元素之间是⽆序的,且集合中的元素不允许重复。⼀个集合中最多可以存储 2^32^− 1 个元素。
普通命令
SADD
将一个或者多个元素添加到set中。
sadd key member [member ...]
时间复杂度为O(1)。返回添加成功的元素个数。
SMEMBERS
获取一个set中的所有元素。
smembers key
时间复杂度为O(N)。返回所有元素的列表。
SISMEMBER
判断一个元素在不在set中。
sismember key member
时间复杂度为O(1)。返回1表示元素在set中,0表示元素不在set中或者键key不存在。
SCARD
获取一个set的基数,即set中的元素的个数。
scard key
时间复杂度O(1)。返回set内的元素个数。
SPOP
从set中删除一个或者多个元素。注意:由于set内的元素是无序的,所有删除哪个元素是随机的。
spop key [count]
时间复杂度是O(N),N为count的值。返回取出的元素。
SRANDMEMBER
随机获取set中指定个数的元素。
srandmember key [count]
时间复杂度为O(N),N为count的值。返回元素的列表。
SMOVE
将一个元素从源set取出并放入目标set中。注意:如果目标set中已经有该元素,源set中依然会移除该元素。
smove source destination member
时间复杂度为O(1)。返回1表示移除成功,如果指定元素在源set中不存在,则返回0表示失败。
SREM
将指定的元素从set中删除。
srem key member [member ...]
时间复杂度O(N),N是要删除的元素个数。返回本次操作删除的元素个数。
集合间操作
SINTER(交集)
获取给定set的交集中的元素。
sinter key [key ...]
时间复杂度O(N*M),N是最小的集合的元素个数,M是最大的集合的元素个数。
返回交集的元素。
SINTERSTORE
获取给定set的交集中的元素并保存到目标set中。
sinterstore destination key [key ...]
时间复杂度同上述SINTER。返回交集的元素个数。
SUNION(并集)
获取给定set的并集中的元素。
sunion key [key ...]
时间复杂度O(N),N是给定的所有集合的总的元素个数。
返回并集的元素。
SUNIONSTORE
获取给定set的并集中的元素并保存到目标set中。
sunionstore destionation key [key ...]
SDIFF
获取给定set的差集中的元素。
sdiff key [key ...]
时间复杂度O(N),N是给定的所有集合的总的元素个数。返回差集的元素。
注意:这里的键的前后顺序的不同,表示的是不同的含义。
SDIFFSTORE
获取给定set的差集中的元素并保存到目标set中。
sdiffstore destination key [key ...]
时间复杂度O(N),N是给定的所有集合的总的元素个数。返回差集的元素个数。
内部编码
集合类型的内部编码有两种:
intset(整数集合):当集合中的元素都是整数并且元素的个数小于set-max-intset-entries配置 (默认512个)时,Redis会选用intset来作为集合的内部实现,从而减少内存的使用。
hashtable(哈希表)::当集合类型无法满足intset的条件时,Redis会使用hashtable作为集合 的内部实现。
适用场景
- 标签系统(Tag):为每个用户或内容打上多个标签(如"娱乐""体育""历史""新闻"),利用 Set 的唯一性存储用户兴趣标签。
- 电商推荐:对不同标签的用户群体做差异化产品推荐。
Zset(有序集合)
它保留了集合不能有重复成员的特点,但与集合不同的是,有序集合中的每个元素都有⼀个唯⼀的浮点类型的分数(score)与之关 联着,使得有序集合中的元素是可以维护有序性的,但这个有序不是用下标作为排序依据而是用这个分数。
这里的有序指的就是升序/降序。
Zset主要还是用来存member的,score只是辅助。
普通命令
ZADD
添加或者更新指定的元素以及关联的分数到zset中,分数应该符合double类型,+inf/-inf为正负无穷大。
zadd key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]
LT:只更新已经存在的元素,新的分数比现在的分数小才会更新成功,且该选项不会阻止添加新的元素。
GT:只更新已经存在的元素,新的分数比现在的分数大才会更新成功,且该选项不会阻止添加新的元素。
CH:默认情况下,zadd返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次更新的元素的个数。
INCR:此时命令类似于下文讲到的ZINCRBY,将元素的分数加上指定的分数。此时只能指定一个元素和一个分数。
时间复杂度为O(log(N))。返回本次添加成功的元素个数。
ZCARD
获取一个zset的基数,即zset中的元素个数。
zcard key
时间复杂度为O(1)。返回zset内的元素个数。
ZRANGE
返回指定区间例的元素,分数按照升序。
zrange key start stop [withscores]
withscores:表示结果显示分数
时间复杂度为O(log(N)+M),N表示zset内的元素个数,M表示区间大小。
返回区间内的元素列表。
此处的[start,stop]为下标构成的区间,从0开始,支持负数。
ZREVRANGE
返回指定区间例的元素,分数按照降序(这个命令在6.2.0之后被标记为弃用,并将功能合并到zrange中)。
zrevrange start stop [withscores]
时间复杂度为O(log(N)+M),N表示zset内的元素个数,M表示区间范围内元素的个数。
返回区间内的元素列表。
ZCOUNT
返回分数在min和max之间的元素个数,默认情况下,min和max都是包含的,可以通过(排除。
zcount key min max
min max:表示[min,max]
(min max:表示(min,max]
min (max:表示[min,max)
(min (max:表示(min,max)
时间复杂度为O(log(N))。返回满足条件的元素列表的个数。
ZRANGEBYSCORE
返回分数在min和max之间的元素,默认情况下,min和max都是包含的,可以通过(排除(这个命令在6.2.0之后被标记为弃用,并将功能合并到zrange中)。
zrangebyscore key min max [withscores]
时间复杂度为O(log(N)+M),N表示zset内的元素个数,M表示区间范围内元素的个数。
返回区间内的元素列表。
ZPOPMAX
删除并返回分数最高的count个元素。
zpopmax key [count]
时间复杂度为O(log(N)*M),M为count的值。返回分数和元素列表。
BZPOPMAX
ZPOPMAX的阻塞版本。
bzpopmax key [key ...] timeout
ZPOPMIN
删除并返回分数最低的count个元素。
zpopmin key [count]
时间复杂度为O(log(N)*M),M为count的值。返回分数和元素列表。
BZPOPMIN
ZPOPMIN的阻塞版本。
bzpopmin key [key ...] timeout
ZRANK
返回指定元素的排名,按照分数升序排名。
zrank key member
时间复杂度为O(log(N))。返回指定元素的排名。
ZREVRANK
返回指定元素的排名,按照分数降序排名。
zrevrank key member
时间复杂度为O(log(N))。返回指定元素的排名。
ZSCORE
返回指定元素的分数。
zscore key member
时间复杂度为O(1)。返回指定元素的分数。
ZREM
删除指定的元素。
zrem key member [member ...]
时间复杂度为O(M*log(N))。返回本次操作删除的元素个数。
ZREMRANGEBYRANK
按照分数升序排序,删除指定下标范围内的元素,左闭右闭。
zremrangebyrank key start stop
时间复杂度为O(log(N)+M),M为指定范围内的元素的个数。
返回本次操作删除的元素个数。
ZREMRANGEBYSCORE
按照分数升序排序,删除指定分数范围内的元素,左闭右闭。
zremrangebyscore key min max
时间复杂度为O(log(N)+M),M为指定范围内的元素的个数。
返回本次操作删除的元素个数。
ZINCRBY
为指定的元素的关联分数添加指定的分数。
zincrby key increment member
时间复杂度为O(log(N))。返回增加后的元素分数。
集合间操作
ZINTER、ZUNION、ZDIFF这几个命令都是在6.2.0之后才开始支持的。
ZINTERSTORE
求出给定有序集合中元素的交集并保存进目标有序集合中,在合并过程中以元素为单位进行合并,元素对应的分数按照不同的聚合方式和权重得到新的分数。
zinterstore destination mumkeys key [key ...] [WEIGHTS weight [weight ...]]
[AGGREGATE <SUM|MIN|MAX>]
weight:表示权重,最后的结果集和的分数,与其对应元素在不同的键中的对应元素的分数和对应的权重的乘积有关。
sum:表示分数是并集结果的分数,是其对应元素在不同的键中的对应的元素的分数的和。
min:表示分数是并集结果的分数,是其对应元素在不同的键中的对应的元素的分数的最小值,
max:表示分数是并集结果的分数,是其对应元素在不同的键中的对应的元素的分数的最大值。
时间复杂度为O(N*K)+O(M*log(M)),N是输入的有序集合中,最小的有序集合的元素个数;K是numkeys的值;M是最终结果的有序集合的元素个数。
返回最终结果的有序集合的元素个数。
这里命令中需要填写numkeys(输入有序集合的个数)的原因是:避免key键和后续对应的选项命令产生混淆。
ZUNIONSTORE
求出给定有序集合中元素的并集并保存进目标有序集合中,在合并过程中以元素为单位进行合并,元素对应的分数按照不同的聚合方式和权重得到新的分数。
zunionstore destionation numkeys key [key ...] [WEIGHTS weight [weight ...]]
[AGGREGATE <sum|max|min>]
时间复杂度为O(N)+O(M*log(M)),N是输入的有序集合总的元素个数;M是最终结果的有序集合的元素个数。
返回目标集合中的元素个数。
内部编码
有序集合类型的内部编码有两种:
ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplist-entries配置(默认128个), 同时每个元素的值都小于zset-max-ziplist-value配置(默认64字节)时,Redis会用ziplist来作为有序集合的内部实现,ziplist可以有效减少内存的使用。
skiplist(跳表):当ziplist条件不满足时,有序集合会使用skiplist作为内部实现,因为此时 ziplist的操作效率会下降。
适用场景
- 排行榜系统:如网站热榜,可按点赞数、阅读量、时间等维度排序。每个元素(如文章 ID)附带分数(如点赞数),ZSet 自动按分数排序,支持快速获取 Top N、指定排名范围的元素。
特殊场景下使用的数据类型
Stream
stream类型是一种日志数据结构,专为消息队列和时间序列场景设计的。每个stream由多个消息组成,每条消息包含一个唯一的ID(时间戳-系列号)和键值对数据。支持消费者组功能,允许多个客户端协同消费消息,并记录已读位置。
核心操作
XADD:追加消息到 Stream。XRANGE/XREVRANGE:按范围读取消息。XREAD:阻塞或非阻塞读取消息。XGROUP:管理消费者组。
适用场景
- 消息队列(替代 Kafka 等中间件)。
- 事件溯源(Event Sourcing)。
Geospatial
geospatial类型用于存储地理位置信息(经纬度),支持距离计算、范围查询等地理空间操作。底层通过sorted set(zset)实现,使用GeoHash编码存储坐标。
核心操作
GEOADD:添加地理位置(经度、纬度、名称)。GEODIST:计算两点间距离。GEORADIUS:查询指定半径内的地点。GEOHASH:获取位置的 GeoHash 值。
适用场景
- 附近的人或地点搜索。
- 配送距离计算。
HyperLogLog
HyperLogLog类型是一种概率算法,用于高效估算集合的基数,误差率约为0.81%。HyperLogLog不存储元素内容,而是记录元素特征,从而在新增元素时,知道新增元素是一个新的元素,还是集合中已经存在的元素,占用固定12KB内存。
核心操作
PFADD:添加元素到 HyperLogLog。PFCOUNT:估算基数。PFMERGE:合并多个 HyperLogLog。
适用场景
- UV(独立访客)统计。
- 大规模数据去重计数。
Bitmap
Bitmap通过位数组存储二进制状态,支持位运算。底层通过String类型实现存储,每个bit代表一个状态,空间效率极高。(类似位图)
核心操作
SETBIT:设置指定位的值。GETBIT:获取指定位的值。BITCOUNT:统计值为 1 的位数。BITOP:执行位运算(交集、并集等)。
适用场景
- 用户签到记录。
- 布尔特征标记(如活跃用户标识)。
Bitfield
Bitfield允许对String类型中的位段进行原子读写和自增操作,适合紧凑存储多个整数字段。支持有符号/无符号整数,指定位宽和偏移量。(类似C语言中的位域)
核心操作
BITFIELD:读写或修改指定位段。- 子命令:
GET/SET/INCRBY。 - 示例:
BITFIELD mykey SET u8 0 100(设置 8 位无符号整数为 100)。
- 子命令:
适用场景
- 紧凑存储多个计数器或标志位。
- 实时指标聚合(如分片统计)。
补充介绍
渐进式遍历
之前介绍过一个命令keys *一次性把整个redis中的所有key都获取到,这个操作是比较危险的,因为redis中可能存在太多的key,导致redis服务器阻塞。
通过渐进式遍历就可以有效避免这个问题。渐进式遍历每执行一次指令,只获取到其中的一小部分,想要得到所有的key就需要多次遍历,即多次执行渐进式遍历命令。
渐进式遍历其实是一组命令,这一组命令的使用方法是一样的,其中的代表命令是scan。
Scan
scan cursor [MATCH pattern] [COUNT count] [TYPE type]
cursor:光标,指向当前遍历的位置
MATCH pattern:和之前Keys命令的pattern是一样的
COUNT count:表示获取的key的数量
TYPE type:表示获取key对应value的类型,代表只获取value为该类型的key
时间复杂度O(1)。
返回值:返回结果包含两部分。第一部分是下一次scan命令的光标位置,第二部分是这次遍历拿到的key的列表。
注意:
1、当命令返回的cuesor回到0了,才说明遍历结束(获取到满足条件的所有key)。
2、这里的光标并非一定是连续递增的,和下标没有什么关系。
3、次数的count只是给redis服务器的一个建议,也就是说写入的count和实际返回的key的个数不一定是完全相同的,但是不会差很多。
4、这里的渐进式遍历,在遍历过程中,不会在服务器这边存储任何的状态信息。这代表着此处的遍历是可以随时终止的,不会对服务器产生任何副作用。
渐进式遍历scan虽然解决了阻塞问题,但如果在遍历期间键有所变化(增加、修改、删除),可能导致遍历时键的重复遍历或者遗漏,这点务必在实际开发中考虑。
数据库管理
之前介绍过Redis可以用作数据库。Redis中的DataBase是现成的,开发人员不能创建新的数据库,也不能删除已有的数据库。
默认Redis给我们提供了16个数据库,编号为0~15。这16个数据库中的数据是隔离的,相互之间不会有影响。
默认情况下我们使用的是编号为0的数据库。
切换数据库
SELECT dbindex
获取当前数据库key的个数
DBSIZE
删除当前数据库中的所有key
flushdb [ASYNC | SYNC]
删除所有数据库中的所有key
flushall [ASYNC | SYNC]