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 和内存资源,因此需要尽量避免。

相关推荐
宁&沉沦6 分钟前
Nginx清除浏览器缓存的三个缓存响应头的关系详解
运维·nginx·缓存
不见长安在21 分钟前
mysql线上主从集群设置
数据库·mysql
tiging23 分钟前
mysql 如何让事件执行
数据库·mysql
siriuuus32 分钟前
MySQL 数据备份
数据库·mysql·备份
姚远Oracle ACE32 分钟前
Oracle AWR 报告中的SQL来自哪儿?
数据库·sql·oracle
熊文豪35 分钟前
KingbaseES数据库性能调优工具全面解析
数据库·kingbasees·金仓数据库·电科金仓
冠希陈、1 小时前
PHP7.4.33 安装sqlsrv扩展
数据库
光影34151 小时前
专利撰写与申请核心要点简报
前端·数据库·php
心灵宝贝1 小时前
申威ky10架构安装MongoDB 4.0.1(rpm包:mongodb-4.0.1-8.ky10.sw_64.rpm)详细步骤
数据库·mongodb·架构
一 乐2 小时前
口腔健康系统|口腔医疗|基于java和小程序的口腔健康系统小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·小程序·毕设