Redis 五种数据类型详解

redis 数据类型详解

本文主要介绍Redis 五种数据结构字符串、哈希、列表、集合、有序集合,本文主要从下面几个方面进行介绍

  • 使用方式
  • 使用场景
  • 内部编码

redis 字符串

命令格式

复制代码
SET key value [EX seconds] [PX milliseconds] [NX|XX]
key:要设置的键名。
value:与键关联的新值。
[EX seconds]:设置键的过期时间(以秒为单位)。
[PX milliseconds]:设置键的过期时间(以毫秒为单位)。
[NX]:仅在键不存在时设置键。
[XX]:仅在键已经存在时设置键。

批量命令

使用 MSETMGET 批量多个键值对操作,批量操作可以减少网络传输时间,一定程度能提升性能,注意由于redis是单线程执行命令,如果一次批量执行命令过多,可能会阻塞其他命令。

使用场景

  • 分布式锁

    通过 NX 选项可以实现分布式锁, 当然如果考虑锁续期,以及分布式下单点故障,可以使用redission 替代。

  • 缓存

    比如缓存用户信息,登录态、

使用demo

复制代码
> SET user:1000 "Alice"
OK
> GET user:1000
"Alice"


# 批量命令

> MSET user:1001 "Bob" user:1002 "Charlie" user:1003 "Diana"
OK

# 同时获取多个用户的姓名
> MGET user:1001 user:1002 user:1003
1) "Bob"
2) "Charlie"
3) "Diana"

内部编码

  • int:

    当字符串是整数,并且可以由 long 类型表示时,Redis 直接将这个整数存储为一个整数值,这种编码非常节省内存,因为不需要额外的 SDS 头部信息。

  • embstr:

    当字符串较短时,Redis 会使用 embstr 编码。,它将 SDS 的头部和数据放在一块连续的内存区域中,这样做可以减少内存碎片,提高缓存局部性。

  • raw:

    对于较长的字符串,Redis 会使用 raw 编码。

    在这种编码下,SDS 的头部和数据是分开分配的。这种方式更灵活,允许对大容量数据进行高效的管理。

综上 Redis字符串类型底层结构不仅仅是SDS,根据情况对空间与时间的折中选择合适的编码格式。

哈希

redis 哈希可以用来存储多个键值对,例如存储用户信息、商品信息等结构化数据

使用demo

复制代码
# 使用HSET命令存储用户信息
HSET user:1000 username "codetonignt"  
HSET user:1000 age 18  
HSET user:1000 email "codetonignt@example.com"

# 使用HGET命令获取用户信息
HGET user:1000 username  # 返回 "codetonignt"  
HGET user:1000 age       # 返回 "18"  
HGET user:1000 email     # 返回 "codetonignt@example.com"

# 使用HGETALL命令获取用户的所有信息
HGETALL user:1000
# 返回 "username" "codetonignt" "age" "18" "email" "codetonignt@example.com"



# HMSET 设置多个字段值
HMSET user:1000 sex man nationality china

# HMGET 获取多个字段值
HMGET user:1000 sex nationality
# 返回  "man"  "china"

性能

hash 可以最多存储(2^32 - 1)个键值对,大多数hash操作时间复杂度是O(1)。HKEYS, HVALS, HGETALL时间复杂度是O(N);

内部编码

  • ziplist:

    当哈希中的字段数量较少,并且每个字段和值的大小都较小时,Redis 会使用 ziplist 编码,它更加节约内存。

  • hashtable:

    当哈希中的字段数量较多或单个字段/值的大小较大时,Redis 会切换到 hashtable 编码。哈希表提供 O(1) 平均时间复杂度的操作性能,但存储空间比ziplist消耗更多。

列表

Redis列表是简单的字符串列表,按照插入顺序排序。支持在两端进行添加或移除元素,列表的最大长度是 2^32 - 1 个元素。

Redis 列表的主要特性包括:

  • 可以在两端插入和删除
  • 列表中元素可以重复
  • 元素是有顺序的
  • BLPOP 和 BRPOP 操作是阻塞的

常见命令

复制代码
LPUSH key value [value ...]:将一个或多个值插入到列表 key 的头部。
RPUSH key value [value ...]:将一个或多个值插入到列表 key 的尾部。
LPOP key:移除并返回列表 key 的头元素。
RPOP key:移除并返回列表 key 的尾元素。
LRANGE key start stop:获取列表 key 中指定范围内的元素,索引从 0 开始。
LLEN key:返回列表 key 的长度。
LINDEX key index:返回列表 key 中,下标为 index 的元素。
LSET key index value:设置列表 key 中下标为 index 的元素的值为 value。
LTRIM key start stop:修剪列表 key,使之只保留指定范围内的元素。
BLPOP key [key ...] timeout:移除并返回第一个非空列表的第一个元素,或者阻塞直到有元素可取或超时。
BRPOP key [key ...] timeout:与 BLPOP 类似,但是是从列表的尾部弹出元素。

内部编码

  • ziplist

    当列表中元素较少,且每个元素都是小正数或者是比较短字符串时,使用ziplist存储,它将多个元素紧凑地存储在一起,减少了内存碎片

  • 双向链表

    否则使用 双向链表实现的:Redis 使用的是双向链表,维护一个长度计数器,因此LLEN key时间复杂度O(1)

相关配置

如果列表中的元素数量超过了 list-max-ziplist-entries 参数设置的值(默认为512)。

或者如果列表中的任何一个元素的大小超过了 list-max-ziplist-value 参数设置的值(默认为64字节)

使用场景

  • 最新消息排行榜
  • 消息队列实现 (利用列表阻塞操作)

性能

list 最多可以有 2^32 - 1 个元素。

LPUSH、LPOP、RPUSH、RPOP 头部或尾部操作时间复杂度是O(1),

LINDEX、 LINSERT、 LSET 时间复杂度是O(N);

同样的如果链表中元素数量过多,同样存在大key问题 ,

(比如使用 LRANGE key start stop 等命令取出所有元素)

集合

Redis 集合是一种无序且不重复的数据结构,类似于Java中的HashSet,它支持交集、并集、差集等功能,用于存储一组字符串元素。

限制:

集合最多可以有 2^32 - 1 (4,294,967,295)个元素

使用示例

复制代码
# 为用户 user1001 添加标签
> SADD user1001:tags "photography" "travel" "food"
(integer) 3

# 为用户 user1001 添加更多标签
> SADD user1001:tags "music"
(integer) 1

# 删除用户 user1001 的某个标签
> SREM user1001:tags "food"
(integer) 1


# 获取用户 user1001 的所有标签
> SMEMBERS user1001:tags
1) "photography"
2) "travel"
3) "music"

# 检查用户 user1001 是否有特定标签
> SISMEMBER user1001:tags "photography"
(integer) 1
> SISMEMBER user1001:tags "sports"
(integer) 0

性能

大多数集合操作包括SADD、SREM和SISMEMBER 时间复杂度都是O(1),SMEMBERS 返回所有元素如果集合中元素过多时应谨慎使用,考虑使用SSCAN替代,对于大数据场景,判断元素是否在集合中可能占大量内存,可以考虑使用bloom过滤器替代。

内部编码

  • intset:

    当集合中的所有元素都是整数,并且集合的大小较小(默认少于512个元素)时,Redis 会使用 intset 编码。intset 是一个有序的整数数组,支持快速查找和插入操作。它在内存中占用的空间较少,并且对小规模的数据集非常高效。

  • hashtable:

    当集合中的元素较多或包含非整数元素时,Redis 会切换到 hashtable 编码。哈希表提供 O(1) 平均时间复杂度的操作性能。

使用场景

可以用集合存储用户标签、好友关系等。

有序集合

Redis有序集合可以存储不重复的字符串成员,并为每个成员关联一个分数(score),以便按分数对成员进行排序。

因此它可以用来实现排行榜、优先级队列等业务场景

使用举例

复制代码
> ZADD leaderboard 100 "user1"
(integer) 1
> ZADD leaderboard 200 "user2" 150 "user3"
(integer) 2


#  ZRANGE key start stop [WITHSCORES] 按照分数从小到大获取指定范围内的成员
> ZRANGE leaderboard 0 2 WITHSCORES
1) "user1"
2) "100"
3) "user3"
4) "150"
5) "user2"
6) "200"




# ZREVRANGE key start stop [WITHSCORES] 按照分数从大到小获取指定范围内的成员

> ZREVRANGE leaderboard 0 2 WITHSCORES
1) "user2"
2) "200"
3) "user3"
4) "150"
5) "user1"
6) "100"

性能

大部分操作时间复杂度是 O(log(n))

内部编码

  • ziplist:

    当有序集合中的元素数量较少,并且每个元素的大小也较小时,Redis 会使用 ziplist 编码。ziplist 非常适合小规模的数据集,因为它在内存中占用的空间较小,并且访问速度较快。

  • skiplist:

    当有序集合中的元素数量较多或单个元素的大小较大时,Redis 会切换到 skiplist 编码。跳表支持高效的范围查询和插入/删除操作,适用于大规模的数据集。

总结

  • 时间与空间兼顾

Redis 底层使用不仅仅考虑效率(时间复杂度),同时也兼顾空间复杂度,因此同一种数据类型,Redis底层编码因存储内容,大小等因素不同,会采用不同的编码进行存储。

  • 合理使用批量命令

Redis 基本是内存操作,因此性能很高,通常多个操作耗时主要在网络传输上,因此redis支持一些批量命令,如mget ,mset 可以有效减少网络传输时间,由于redis 是当线程模型,批量命令也不能滥用,一次批量键值对也不能过多,否则会阻塞其他命令。

  • 大Key问题

大key指占用大量内存的键,如很长的字符串,列表元素过多。访问或操作大Key,会导致 Redis 服务器阻塞一段时间,同时会消耗大量的 CPU 和内存资源,因此需要尽量避免。

相关推荐
一码归一码@35 分钟前
Mysql进阶之事务原理
数据库·mysql
老邓计算机毕设8 小时前
SSM学生选课系统xvbna(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·学生选课系统·ssm 框架·高校教学管理
難釋懷8 小时前
SpringDataRedis数据序列化器
redis·缓存
枷锁—sha8 小时前
【PortSwigger Academy】SQL 注入绕过登录 (Login Bypass)
数据库·sql·学习·安全·网络安全
逍遥德10 小时前
PostgreSQL 中唯一约束(UNIQUE CONSTRAINT) 和唯一索引(UNIQUE INDEX) 的核心区别
数据库·sql·postgresql·dba
工业甲酰苯胺10 小时前
字符串分割并展开成表格的SQL实现方法
数据库·sql
科技块儿11 小时前
IP定位技术:游戏反外挂体系中的精准识别引擎
数据库·tcp/ip·游戏
衫水11 小时前
[特殊字符] MySQL 常用指令大全
数据库·mysql·oracle
卓怡学长11 小时前
m115乐购游戏商城系统
java·前端·数据库·spring boot·spring·游戏
小句12 小时前
SQL中JOIN语法详解 GROUP BY语法详解
数据库·sql